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; }
static int vboxvfs_unmount(struct mount *mp, int mntflags, struct thread *td) { struct sf_glob_info *pShFlGlobalInfo = VFSMP2SFGLOBINFO(mp); int rc; int flags = 0; rc = VbglR0SfUnmapFolder(&g_vboxSFClient, &pShFlGlobalInfo->map); if (RT_FAILURE(rc)) printf("Failed to unmap shared folder\n"); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; /* There is 1 extra root vnode reference (vnode_root). */ rc = vflush(mp, 1, flags, td); if (rc) return rc; RTMemFree(pShFlGlobalInfo); mp->mnt_data = NULL; return 0; }
/* * Free reference to umap layer */ int umapfs_unmount(struct mount *mp, int mntflags) { struct umap_mount *amp = MOUNTTOUMAPMOUNT(mp); struct vnode *rtvp = amp->umapm_rootvp; int error; int flags = 0; #ifdef UMAPFS_DIAGNOSTIC printf("umapfs_unmount(mp = %p)\n", mp); #endif if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if (rtvp->v_usecount > 1 && (mntflags & MNT_FORCE) == 0) return (EBUSY); if ((error = vflush(mp, rtvp, flags)) != 0) return (error); #ifdef UMAPFS_DIAGNOSTIC vprint("alias root of lower", rtvp); #endif /* * Blow it away for future re-use */ vgone(rtvp); /* * Finally, throw away the umap_mount structure */ mutex_destroy(&->umapm_hashlock); hashdone(amp->umapm_node_hashtbl, HASH_LIST, amp->umapm_node_hash); kmem_free(amp, sizeof(struct umap_mount)); mp->mnt_data = NULL; return 0; }
/* * unmount system call */ static int devfs_vfs_unmount(struct mount *mp, int mntflags) { int error = 0; int flags = 0; devfs_debug(DEVFS_DEBUG_DEBUG, "(vfsops) devfs_unmount() called!\n"); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, 0, flags); if (error) return (error); lockmgr(&devfs_lock, LK_EXCLUSIVE); devfs_tracer_orphan_count(mp, 1); lockmgr(&devfs_lock, LK_RELEASE); devfs_mount_del(DEVFS_MNTDATA(mp)); kfree(mp->mnt_data, M_DEVFS); mp->mnt_data = NULL; return (0); }
/* * 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); }
/*ARGSUSED*/ static int zfs_vfs_unmount(struct mount *mp, int mntflags, vfs_context_t context) { zfsvfs_t *zfsvfs = vfs_fsprivate(mp); objset_t *os = zfsvfs->z_os; znode_t *zp, *nextzp; int ret, i; int flags; /*XXX NOEL: delegation admin stuffs, add back if we use delg. admin */ #if 0 ret = 0; /* UNDEFINED: secpolicy_fs_unmount(cr, vfsp); */ if (ret) { ret = dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource), ZFS_DELEG_PERM_MOUNT, cr); if (ret) return (ret); } /* * We purge the parent filesystem's vfsp as the parent filesystem * and all of its snapshots have their vnode's v_vfsp set to the * parent's filesystem's vfsp. Note, 'z_parent' is self * referential for non-snapshots. */ (void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0); #endif /* * Unmount any snapshots mounted under .zfs before unmounting the * dataset itself. */ #if 0 if (zfsvfs->z_ctldir != NULL && (ret = zfsctl_umount_snapshots(vfsp, fflag, cr)) != 0) { return (ret); #endif flags = SKIPSYSTEM; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; ret = vflush(mp, NULLVP, flags); /* * Mac OS X needs a file system modify time * * We use the mtime of the "com.apple.system.mtime" * extended attribute, which is associated with the * file system root directory. * * Here we need to release the ref we took on z_mtime_vp during mount. */ if ((ret == 0) || (mntflags & MNT_FORCE)) { if (zfsvfs->z_mtime_vp != NULL) { struct vnode *mvp; mvp = zfsvfs->z_mtime_vp; zfsvfs->z_mtime_vp = NULL; if (vnode_get(mvp) == 0) { vnode_rele(mvp); vnode_recycle(mvp); vnode_put(mvp); } } } if (!(mntflags & MNT_FORCE)) { /* * Check the number of active vnodes in the file system. * Our count is maintained in the vfs structure, but the * number is off by 1 to indicate a hold on the vfs * structure itself. * * The '.zfs' directory maintains a reference of its * own, and any active references underneath are * reflected in the vnode count. */ if (ret) return (EBUSY); #if 0 if (zfsvfs->z_ctldir == NULL) { if (vfsp->vfs_count > 1) return (EBUSY); } else { if (vfsp->vfs_count > 2 || zfsvfs->z_ctldir->v_count > 1) { return (EBUSY); } } #endif } rw_enter(&zfsvfs->z_unmount_lock, RW_WRITER); rw_enter(&zfsvfs->z_unmount_inactive_lock, RW_WRITER); /* * At this point there are no vops active, and any new vops will * fail with EIO since we have z_unmount_lock for writer (only * relavent for forced unmount). * * Release all holds on dbufs. * Note, the dmu can still callback via znode_pageout_func() * which can zfs_znode_free() the znode. So we lock * z_all_znodes; search the list for a held dbuf; drop the lock * (we know zp can't disappear if we hold a dbuf lock) then * regrab the lock and restart. */ mutex_enter(&zfsvfs->z_znodes_lock); for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = nextzp) { nextzp = list_next(&zfsvfs->z_all_znodes, zp); if (zp->z_dbuf_held) { /* dbufs should only be held when force unmounting */ zp->z_dbuf_held = 0; mutex_exit(&zfsvfs->z_znodes_lock); dmu_buf_rele(zp->z_dbuf, NULL); /* Start again */ mutex_enter(&zfsvfs->z_znodes_lock); nextzp = list_head(&zfsvfs->z_all_znodes); } } mutex_exit(&zfsvfs->z_znodes_lock); /* * Set the unmounted flag and let new vops unblock. * zfs_inactive will have the unmounted behavior, and all other * vops will fail with EIO. */ zfsvfs->z_unmounted = B_TRUE; rw_exit(&zfsvfs->z_unmount_lock); rw_exit(&zfsvfs->z_unmount_inactive_lock); /* * Unregister properties. */ #ifndef __APPLE__ if (!dmu_objset_is_snapshot(os)) zfs_unregister_callbacks(zfsvfs); #endif /* * Close the zil. NB: Can't close the zil while zfs_inactive * threads are blocked as zil_close can call zfs_inactive. */ if (zfsvfs->z_log) { zil_close(zfsvfs->z_log); zfsvfs->z_log = NULL; } /* * Evict all dbufs so that cached znodes will be freed */ if (dmu_objset_evict_dbufs(os, B_TRUE)) { txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0); (void) dmu_objset_evict_dbufs(os, B_FALSE); } /* * Finally close the objset */ dmu_objset_close(os); /* * We can now safely destroy the '.zfs' directory node. */ #if 0 if (zfsvfs->z_ctldir != NULL) zfsctl_destroy(zfsvfs); #endif /* * Note that this work is normally done in zfs_freevfs, but since * there is no VOP_FREEVFS in OSX, we free VFS items here */ OSDecrementAtomic((SInt32 *)&zfs_active_fs_count); for (i = 0; i != ZFS_OBJ_MTX_SZ; i++) mutex_destroy(&zfsvfs->z_hold_mtx[i]); mutex_destroy(&zfsvfs->z_znodes_lock); list_destroy(&zfsvfs->z_all_znodes); rw_destroy(&zfsvfs->z_unmount_lock); rw_destroy(&zfsvfs->z_unmount_inactive_lock); return (0); } struct vnode* vnode_getparent(struct vnode *vp); /* sys/vnode_internal.h */ static int zfs_vget_internal(zfsvfs_t *zfsvfs, ino64_t ino, struct vnode **vpp) { struct vnode *vp; struct vnode *dvp = NULL; znode_t *zp; int error; *vpp = NULL; /* * On Mac OS X we always export the root directory id as 2 * and its parent as 1 */ if (ino == 2 || ino == 1) ino = zfsvfs->z_root; if ((error = zfs_zget(zfsvfs, ino, &zp))) goto out; /* Don't expose EA objects! */ if (zp->z_phys->zp_flags & ZFS_XATTR) { vnode_put(ZTOV(zp)); error = ENOENT; goto out; } *vpp = vp = ZTOV(zp); if (vnode_isvroot(vp)) goto out; /* * If this znode didn't just come from the cache then * it won't have a valid identity (parent and name). * * Manually fix its identity here (normally done by namei lookup). */ if ((dvp = vnode_getparent(vp)) == NULL) { if (zp->z_phys->zp_parent != 0 && zfs_vget_internal(zfsvfs, zp->z_phys->zp_parent, &dvp)) { goto out; } if ( vnode_isdir(dvp) ) { char objname[ZAP_MAXNAMELEN]; /* 256 bytes */ int flags = VNODE_UPDATE_PARENT; /* Look for znode's name in its parent's zap */ if ( zap_value_search(zfsvfs->z_os, zp->z_phys->zp_parent, zp->z_id, ZFS_DIRENT_OBJ(-1ULL), objname) == 0 ) { flags |= VNODE_UPDATE_NAME; } /* Update the znode's parent and name */ vnode_update_identity(vp, dvp, objname, 0, 0, flags); } } /* All done with znode's parent */ vnode_put(dvp); out: return (error); } /* * Get a vnode from a file id (ignoring the generation) * * Use by NFS Server (readdirplus) and VFS (build_path) */ static int zfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context) { zfsvfs_t *zfsvfs = vfs_fsprivate(mp); int error; ZFS_ENTER(zfsvfs); /* * On Mac OS X we always export the root directory id as 2. * So we don't expect to see the real root directory id * from zfs_vfs_vget KPI (unless of course the real id was * already 2). */ if ((ino == zfsvfs->z_root) && (zfsvfs->z_root != 2)) { ZFS_EXIT(zfsvfs); return (ENOENT); } error = zfs_vget_internal(zfsvfs, ino, vpp); ZFS_EXIT(zfsvfs); return (error); }
static int ntfs_unmount(struct mount *mp, int mntflags) { struct ntfsmount *ntmp; int error, ronly, flags, i; dprintf(("ntfs_unmount: unmounting...\n")); ntmp = VFSTONTFS(mp); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; flags = 0; if(mntflags & MNT_FORCE) flags |= FORCECLOSE; dprintf(("ntfs_unmount: vflushing...\n")); error = vflush(mp, 0, flags | SKIPSYSTEM); if (error) { kprintf("ntfs_unmount: vflush failed: %d\n",error); return (error); } /* Check if only system vnodes are left */ for(i=0;i<NTFS_SYSNODESNUM;i++) if((ntmp->ntm_sysvn[i]) && (VREFCNT(ntmp->ntm_sysvn[i]) > 1)) return (EBUSY); /* Dereference all system vnodes */ for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); /* vflush system vnodes */ error = vflush(mp, 0, flags); if (error) kprintf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); /* Check if the type of device node isn't VBAD before * touching v_cdevinfo. If the device vnode is revoked, the * field is NULL and touching it causes null pointer derefercence. */ if (ntmp->ntm_devvp->v_type != VBAD) ntmp->ntm_devvp->v_rdev->si_mountpoint = NULL; vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); vinvalbuf(ntmp->ntm_devvp, V_SAVE, 0, 0); error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, NULL); vn_unlock(ntmp->ntm_devvp); vrele(ntmp->ntm_devvp); /* free the toupper table, if this has been last mounted ntfs volume */ ntfs_toupper_unuse(); dprintf(("ntfs_umount: freeing memory...\n")); ntfs_u28_uninit(ntmp); ntfs_82u_uninit(ntmp); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; kfree(ntmp->ntm_ad, M_NTFSMNT); kfree(ntmp, M_NTFSMNT); return (error); }
/* * Common code for mount and mountroot */ int ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct ucred *cred) { struct buf *bp; struct ntfsmount *ntmp; cdev_t dev; int error, ronly, ncount, i; struct vnode *vp; char cs_local[ICONV_CSNMAXLEN]; char cs_ntfs[ICONV_CSNMAXLEN]; /* * 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. */ error = vfs_mountedon(devvp); if (error) return (error); ncount = vcount(devvp); if (devvp->v_object) ncount -= 1; if (ncount > 1) return (EBUSY); VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, 0, 0); VOP__UNLOCK(devvp, 0); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL); VOP__UNLOCK(devvp, 0); if (error) return (error); dev = devvp->v_rdev; bp = NULL; error = bread(devvp, BBLOCK, BBSIZE, &bp); if (error) goto out; ntmp = kmalloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO); bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) ); /* * We must not cache the boot block if its size is not exactly * one cluster in order to avoid confusing the buffer cache when * the boot file is read later by ntfs_readntvattr_plain(), which * reads a cluster at a time. */ if (ntfs_cntob(1) != BBSIZE) bp->b_flags |= B_NOCACHE; brelse( bp ); bp = NULL; if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { error = EINVAL; dprintf(("ntfs_mountfs: invalid boot block\n")); goto out; } { int8_t cpr = ntmp->ntm_mftrecsz; if( cpr > 0 ) ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; else ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; } dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); ntmp->ntm_mountp = mp; ntmp->ntm_dev = dev; ntmp->ntm_devvp = devvp; ntmp->ntm_uid = argsp->uid; ntmp->ntm_gid = argsp->gid; ntmp->ntm_mode = argsp->mode; ntmp->ntm_flag = argsp->flag; if (argsp->flag & NTFS_MFLAG_KICONV && ntfs_iconv) { bcopy(argsp->cs_local, cs_local, sizeof(cs_local)); bcopy(argsp->cs_ntfs, cs_ntfs, sizeof(cs_ntfs)); ntfs_82u_init(ntmp, cs_local, cs_ntfs); ntfs_u28_init(ntmp, NULL, cs_local, cs_ntfs); } else { ntfs_82u_init(ntmp, NULL, NULL); ntfs_u28_init(ntmp, ntmp->ntm_82u, NULL, NULL); } mp->mnt_data = (qaddr_t)ntmp; dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); vfs_add_vnodeops(mp, &ntfs_vnode_vops, &mp->mnt_vn_norm_ops); /* * We read in some system nodes to do not allow * reclaim them and to have everytime access to them. */ { int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; for (i=0; i<3; i++) { error = VFS_VGET(mp, NULL, pi[i], &(ntmp->ntm_sysvn[pi[i]])); if(error) goto out1; vsetflags(ntmp->ntm_sysvn[pi[i]], VSYSTEM); vref(ntmp->ntm_sysvn[pi[i]]); vput(ntmp->ntm_sysvn[pi[i]]); } } /* read the Unicode lowercase --> uppercase translation table, * if necessary */ if ((error = ntfs_toupper_use(mp, ntmp))) goto out1; /* * Scan $BitMap and count free clusters */ error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); if(error) goto out1; /* * Read and translate to internal format attribute * definition file. */ { int num,j; struct attrdef ad; /* Open $AttrDef */ error = VFS_VGET(mp, NULL, NTFS_ATTRDEFINO, &vp); if(error) goto out1; /* Count valid entries */ for(num=0;;num++) { error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; if (ad.ad_name[0] == 0) break; } /* Alloc memory for attribute definitions */ ntmp->ntm_ad = kmalloc(num * sizeof(struct ntvattrdef), M_NTFSMNT, M_WAITOK); ntmp->ntm_adnum = num; /* Read them and translate */ for(i=0;i<num;i++){ error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; j = 0; do { ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; } while(ad.ad_name[j++]); ntmp->ntm_ad[i].ad_namelen = j - 1; ntmp->ntm_ad[i].ad_type = ad.ad_type; } vput(vp); } mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = 0; mp->mnt_flag |= MNT_LOCAL; dev->si_mountpoint = mp; return (0); out1: for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); if (vflush(mp, 0, 0)) dprintf(("ntfs_mountfs: vflush failed\n")); out: dev->si_mountpoint = NULL; if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NULL); vn_unlock(devvp); return (error); }
/*ARGSUSED*/ static int zfs_umount(vfs_t *vfsp, int fflag) { zfsvfs_t *zfsvfs = vfsp->vfs_data; objset_t *os; cred_t *cr = curthread->td_ucred; int ret; ret = secpolicy_fs_unmount(cr, vfsp); if (ret) { ret = dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource), ZFS_DELEG_PERM_MOUNT, cr); if (ret) return (ret); } /* * We purge the parent filesystem's vfsp as the parent filesystem * and all of its snapshots have their vnode's v_vfsp set to the * parent's filesystem's vfsp. Note, 'z_parent' is self * referential for non-snapshots. */ (void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0); /* * Unmount any snapshots mounted under .zfs before unmounting the * dataset itself. */ if (zfsvfs->z_ctldir != NULL) { if ((ret = zfsctl_umount_snapshots(vfsp, fflag, cr)) != 0) return (ret); ret = vflush(vfsp, 0, 0, curthread); ASSERT(ret == EBUSY); if (!(fflag & MS_FORCE)) { if (zfsvfs->z_ctldir->v_count > 1) return (EBUSY); ASSERT(zfsvfs->z_ctldir->v_count == 1); } zfsctl_destroy(zfsvfs); ASSERT(zfsvfs->z_ctldir == NULL); } if (fflag & MS_FORCE) { /* * Mark file system as unmounted before calling * vflush(FORCECLOSE). This way we ensure no future vnops * will be called and risk operating on DOOMED vnodes. */ rrw_enter(&zfsvfs->z_teardown_lock, RW_WRITER, FTAG); zfsvfs->z_unmounted = B_TRUE; rrw_exit(&zfsvfs->z_teardown_lock, FTAG); } /* * Flush all the files. */ ret = vflush(vfsp, 1, (fflag & MS_FORCE) ? FORCECLOSE : 0, curthread); if (ret != 0) { if (!zfsvfs->z_issnap) { zfsctl_create(zfsvfs); ASSERT(zfsvfs->z_ctldir != NULL); } return (ret); } if (!(fflag & MS_FORCE)) { /* * Check the number of active vnodes in the file system. * Our count is maintained in the vfs structure, but the * number is off by 1 to indicate a hold on the vfs * structure itself. * * The '.zfs' directory maintains a reference of its * own, and any active references underneath are * reflected in the vnode count. */ if (zfsvfs->z_ctldir == NULL) { if (vfsp->vfs_count > 1) return (EBUSY); } else { if (vfsp->vfs_count > 2 || zfsvfs->z_ctldir->v_count > 1) return (EBUSY); } } else { MNT_ILOCK(vfsp); vfsp->mnt_kern_flag |= MNTK_UNMOUNTF; MNT_IUNLOCK(vfsp); } VERIFY(zfsvfs_teardown(zfsvfs, B_TRUE) == 0); os = zfsvfs->z_os; /* * z_os will be NULL if there was an error in * attempting to reopen zfsvfs. */ if (os != NULL) { /* * Unset the objset user_ptr. */ mutex_enter(&os->os->os_user_ptr_lock); dmu_objset_set_user(os, NULL); mutex_exit(&os->os->os_user_ptr_lock); /* * Finally release the objset */ dmu_objset_close(os); } /* * We can now safely destroy the '.zfs' directory node. */ if (zfsvfs->z_ctldir != NULL) zfsctl_destroy(zfsvfs); if (zfsvfs->z_issnap) { vnode_t *svp = vfsp->mnt_vnodecovered; if (svp->v_count >= 2) VN_RELE(svp); } zfs_freevfs(vfsp); return (0); }
/* * Common code for mount and mountroot */ int ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct lwp *l) { struct buf *bp; struct ntfsmount *ntmp; dev_t dev = devvp->v_rdev; int error, i; struct vnode *vp; ntmp = NULL; /* * Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return (error); bp = NULL; error = bread(devvp, BBLOCK, BBSIZE, NOCRED, 0, &bp); if (error) goto out; ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK|M_ZERO); memcpy( &ntmp->ntm_bootfile, bp->b_data, sizeof(struct bootfile) ); brelse( bp , 0 ); bp = NULL; if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { error = EINVAL; dprintf(("ntfs_mountfs: invalid boot block\n")); goto out; } { int8_t cpr = ntmp->ntm_mftrecsz; if( cpr > 0 ) ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; else ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; } dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); ntmp->ntm_mountp = mp; ntmp->ntm_dev = dev; ntmp->ntm_devvp = devvp; ntmp->ntm_uid = argsp->uid; ntmp->ntm_gid = argsp->gid; ntmp->ntm_mode = argsp->mode; ntmp->ntm_flag = argsp->flag; mp->mnt_data = ntmp; /* set file name encode/decode hooks XXX utf-8 only for now */ ntmp->ntm_wget = ntfs_utf8_wget; ntmp->ntm_wput = ntfs_utf8_wput; ntmp->ntm_wcmp = ntfs_utf8_wcmp; dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); /* * We read in some system nodes to do not allow * reclaim them and to have everytime access to them. */ { int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; for (i=0; i<3; i++) { error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]])); if(error) goto out1; ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM; vref(ntmp->ntm_sysvn[pi[i]]); vput(ntmp->ntm_sysvn[pi[i]]); } } /* read the Unicode lowercase --> uppercase translation table, * if necessary */ if ((error = ntfs_toupper_use(mp, ntmp))) goto out1; /* * Scan $BitMap and count free clusters */ error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); if(error) goto out1; /* * Read and translate to internal format attribute * definition file. */ { int num,j; struct attrdef ad; /* Open $AttrDef */ error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); if(error) goto out1; /* Count valid entries */ for(num=0;;num++) { error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; if (ad.ad_name[0] == 0) break; } /* Alloc memory for attribute definitions */ ntmp->ntm_ad = (struct ntvattrdef *) malloc( num * sizeof(struct ntvattrdef), M_NTFSMNT, M_WAITOK); ntmp->ntm_adnum = num; /* Read them and translate */ for(i=0;i<num;i++){ error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; j = 0; do { ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; } while(ad.ad_name[j++]); ntmp->ntm_ad[i].ad_namelen = j - 1; ntmp->ntm_ad[i].ad_type = ad.ad_type; } vput(vp); } mp->mnt_stat.f_fsidx.__fsid_val[0] = dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_NTFS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = NTFS_MAXFILENAME; mp->mnt_flag |= MNT_LOCAL; spec_node_setmountedfs(devvp, mp); return (0); out1: for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); if (vflush(mp,NULLVP,0)) { dprintf(("ntfs_mountfs: vflush failed\n")); } out: spec_node_setmountedfs(devvp, NULL); if (bp) brelse(bp, 0); if (error) { if (ntmp) { if (ntmp->ntm_ad) free(ntmp->ntm_ad, M_NTFSMNT); free(ntmp, M_NTFSMNT); } } return (error); }
/* * mp - path - addr in user space of mount point (ie /usr or whatever) * data - addr in user space of mount params including the name of the block * special file to treat as a filesystem. */ static int msdosfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) { struct vnode *devvp; /* vnode for blk device to mount */ struct msdosfs_args args; /* will hold data from mount request */ /* msdosfs specific mount control block */ struct msdosfsmount *pmp = NULL; size_t size; int error, flags; mode_t accessmode; struct nlookupdata nd; error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); if (error) return (error); if (args.magic != MSDOSFS_ARGSMAGIC) args.flags = 0; /* * 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) { pmp = VFSTOMSDOSFS(mp); error = 0; if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, 0, flags); if (error == 0) { devvp = pmp->pm_devvp; VOP_OPEN(devvp, FREAD, FSCRED, NULL); VOP_CLOSE(devvp, FREAD|FWRITE); pmp->pm_flags |= MSDOSFSMNT_RONLY; } } if (!error && (mp->mnt_flag & MNT_RELOAD)) /* not yet implemented */ error = EOPNOTSUPP; if (error) return (error); if ((pmp->pm_flags & MSDOSFSMNT_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. */ devvp = pmp->pm_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); if (cred->cr_uid != 0) { error = VOP_EACCESS(devvp, VREAD | VWRITE, cred); if (error) { vn_unlock(devvp); return (error); } } VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, NULL); VOP_CLOSE(devvp, FREAD); vn_unlock(devvp); pmp->pm_flags &= ~MSDOSFSMNT_RONLY; } if (args.fspec == 0) { #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ if (args.flags & MSDOSFSMNT_MNTOPT) { pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; } #endif /* * Process export requests. */ return (vfs_export(mp, &pmp->pm_export, &args.export)); } }
/* * mp - path - addr in user space of mount point (ie /usr or whatever) * data - addr in user space of mount params including the name of the block * special file to treat as a filesystem. */ int msdosfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) { struct lwp *l = curlwp; struct vnode *devvp; /* vnode for blk device to mount */ struct msdosfs_args *args = data; /* holds data from mount request */ /* msdosfs specific mount control block */ struct msdosfsmount *pmp = NULL; int error, flags; mode_t accessmode; if (*data_len < sizeof *args) return EINVAL; if (mp->mnt_flag & MNT_GETARGS) { pmp = VFSTOMSDOSFS(mp); if (pmp == NULL) return EIO; args->fspec = NULL; args->uid = pmp->pm_uid; args->gid = pmp->pm_gid; args->mask = pmp->pm_mask; args->flags = pmp->pm_flags; args->version = MSDOSFSMNT_VERSION; args->dirmask = pmp->pm_dirmask; args->gmtoff = pmp->pm_gmtoff; *data_len = sizeof *args; return 0; } /* * If not versioned (i.e. using old mount_msdos(8)), fill in * the additional structure items with suitable defaults. */ if ((args->flags & MSDOSFSMNT_VERSIONED) == 0) { args->version = 1; args->dirmask = args->mask; } /* * Reset GMT offset for pre-v3 mount structure args. */ if (args->version < 3) args->gmtoff = 0; /* * 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) { pmp = VFSTOMSDOSFS(mp); error = 0; if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, NULLVP, flags); } if (!error && (mp->mnt_flag & MNT_RELOAD)) /* not yet implemented */ error = EOPNOTSUPP; if (error) { DPRINTF(("vflush %d\n", error)); return (error); } if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_iflag & IMNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. * * Permission to update a mount is checked higher, so * here we presume updating the mount is okay (for * example, as far as securelevel goes) which leaves us * with the normal check. */ devvp = pmp->pm_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(VREAD | VWRITE)); VOP_UNLOCK(devvp); DPRINTF(("KAUTH_REQ_SYSTEM_MOUNT_DEVICE %d\n", error)); if (error) return (error); pmp->pm_flags &= ~MSDOSFSMNT_RONLY; } if (args->fspec == NULL) { DPRINTF(("missing fspec\n")); return EINVAL; } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ error = namei_simple_user(args->fspec, NSM_FOLLOW_NOEMULROOT, &devvp); if (error != 0) { DPRINTF(("namei %d\n", error)); return (error); } if (devvp->v_type != VBLK) { DPRINTF(("not block\n")); vrele(devvp); return (ENOTBLK); } if (bdevsw_lookup(devvp->v_rdev) == NULL) { DPRINTF(("no block switch\n")); vrele(devvp); return (ENXIO); } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode)); VOP_UNLOCK(devvp); if (error) { DPRINTF(("KAUTH_REQ_SYSTEM_MOUNT_DEVICE %d\n", error)); vrele(devvp); return (error); } if ((mp->mnt_flag & MNT_UPDATE) == 0) { int xflags; if (mp->mnt_flag & MNT_RDONLY) xflags = FREAD; else xflags = FREAD|FWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_OPEN(devvp, xflags, FSCRED); VOP_UNLOCK(devvp); if (error) { DPRINTF(("VOP_OPEN %d\n", error)); goto fail; } error = msdosfs_mountfs(devvp, mp, l, args); if (error) { DPRINTF(("msdosfs_mountfs %d\n", error)); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); (void) VOP_CLOSE(devvp, xflags, NOCRED); VOP_UNLOCK(devvp); goto fail; } #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ pmp = VFSTOMSDOSFS(mp); #endif } else { vrele(devvp); if (devvp != pmp->pm_devvp) { DPRINTF(("devvp %p pmp %p\n", devvp, pmp->pm_devvp)); return (EINVAL); /* needs translation */ } } if ((error = update_mp(mp, args)) != 0) { msdosfs_unmount(mp, MNT_FORCE); DPRINTF(("update_mp %d\n", error)); return error; } #ifdef MSDOSFS_DEBUG printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); #endif return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); fail: vrele(devvp); return (error); }
void vdstco_(int *num, int index_array[], float color_array[][3], int *color_mod) { int i = 0; int start_index = 0; int hld_colors_ptr = 0; int first = 0; int count = 0; int hld_colors[768]; if (*num < 1 || *num > dev_cap[3]) { vdicgi_errh(" SVDI Shell (VDSTCO) Error Number 723, Severity Code 5 "); return; } if (*color_mod != 0 && *color_mod != 1) { vdicgi_errh(" SVDI Shell (VDSTCO) Error Number 725, Severity Code 5 "); return; } vflush(); /* flush polyline buffer */ first = TRUE; for (i = 0; i < *num; i++) { if (index_array[i] < 0 || index_array[i] > 255) vdicgi_errh(" SVDI Shell (VDSTCO) Error Number 724, Severity Code 5 "); /* Set RGB color */ else if (*color_mod == 0) { if (color_array[i][0] < 0. || color_array[i][0] > 1. || color_array[i][1] < 0. || color_array[i][1] > 1. || color_array[i][2] < 0. || color_array[i][2] > 1.) vdicgi_errh(" SVDI Shell (VDSTCO) Error Number 727, Severity Code 5 "); else /* Check to see if indices are consecutive (buffer up if they are) */ { if (first) { /* set color table from index requested + 2 (0 reserved for background) */ start_index = index_array[i] + 2; hld_colors_ptr = 0; first = FALSE; } hld_colors[hld_colors_ptr++] = (int)(color_array[i][0] * color_scale); hld_colors[hld_colors_ptr++] = (int)(color_array[i][1] * color_scale); hld_colors[hld_colors_ptr++] = (int)(color_array[i][2] * color_scale); if (i < *num - 1) { if (index_array[i] != (index_array[i + 1] - 1)) { count = hld_colors_ptr / 3; cct_(&start_index, &count, hld_colors); first = TRUE; } } } } /* Set HLS color (HLS not supported) */ else { vdicgi_errh(" SVDI Shell (VDSTCO) HLS option being phased out - ignored "); vdicgi_errh(" Contact Computer Graphics Group - Div. 2644 "); } } count = hld_colors_ptr / 3; if (count > 0) cct_(&start_index, &count, hld_colors); }
void vdterm_() { vflush(); ct_(); }
static int fuse_vfsop_unmount(struct mount *mp, int mntflags) { int err = 0; int flags = 0; struct cdev *fdev; struct fuse_data *data; struct fuse_dispatcher fdi; struct thread *td = curthread; fuse_trace_printf_vfsop(); if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } data = fuse_get_mpdata(mp); if (!data) { panic("no private data for mount point?"); } /* There is 1 extra root vnode reference (mp->mnt_data). */ FUSE_LOCK(); if (data->vroot != NULL) { struct vnode *vroot = data->vroot; data->vroot = NULL; FUSE_UNLOCK(); vrele(vroot); } else FUSE_UNLOCK(); err = vflush(mp, 0, flags, td); if (err) { debug_printf("vflush failed"); return err; } if (fdata_get_dead(data)) { goto alreadydead; } fdisp_init(&fdi, 0); fdisp_make(&fdi, FUSE_DESTROY, mp, 0, td, NULL); err = fdisp_wait_answ(&fdi); fdisp_destroy(&fdi); fdata_set_dead(data); alreadydead: FUSE_LOCK(); data->mp = NULL; fdev = data->fdev; fdata_trydestroy(data); FUSE_UNLOCK(); MNT_ILOCK(mp); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; MNT_IUNLOCK(mp); dev_rel(fdev); return 0; }
VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount int mntflags, // IN: unmount(2) flags (ex: MNT_FORCE) struct thread *td) // IN: caller's kernel thread context #endif { struct VMBlockMount *xmp; struct vnode *vp; void *mntdata; int error; int flags = 0, removed = 0; VMBLOCKDEBUG("VMBlockVFSUnmount: mp = %p\n", (void *)mp); xmp = MNTTOVMBLOCKMNT(mp); vp = xmp->rootVnode; VI_LOCK(vp); /* * VMBlocks reference the root vnode. This check returns EBUSY if * VMBlocks still exist & the user isn't forcing us out. */ if ((vp->v_usecount > 1) && !(mntflags & MNT_FORCE)) { VI_UNLOCK(vp); return EBUSY; } /* * FreeBSD forbids acquiring sleepable locks (ex: sx locks) while holding * non-sleepable locks (ex: mutexes). The vnode interlock acquired above * is a mutex, and the Block* routines involve sx locks, so we need to * yield the interlock. * * In order to do this safely, we trade up to locking the entire vnode, * and indicate to the lock routine that we hold the interlock. The lock * transfer will happen atomically. (Er, at least within the scope of * the vnode subsystem.) */ COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, compat_td); removed = BlockRemoveAllBlocks(OS_UNKNOWN_BLOCKER); VI_LOCK(vp); vp->v_usecount -= removed; VI_UNLOCK(vp); COMPAT_VOP_UNLOCK(vp, 0, compat_td); if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } /* There is 1 extra root vnode reference (xmp->rootVnode). */ error = vflush(mp, 1, flags, compat_td); if (error) { return error; } /* * Finally, throw away the VMBlockMount structure */ mntdata = mp->mnt_data; mp->mnt_data = 0; free(mntdata, M_VMBLOCKFSMNT); return 0; }
static int ntfs_unmount( struct mount *mp, int mntflags) { struct lwp *l = curlwp; struct ntfsmount *ntmp; int error, ronly = 0, flags, i; dprintf(("ntfs_unmount: unmounting...\n")); ntmp = VFSTONTFS(mp); flags = 0; if(mntflags & MNT_FORCE) flags |= FORCECLOSE; dprintf(("ntfs_unmount: vflushing...\n")); error = vflush(mp,NULLVP,flags | SKIPSYSTEM); if (error) { dprintf(("ntfs_unmount: vflush failed: %d\n",error)); return (error); } /* Check if only system vnodes are rest */ for(i=0;i<NTFS_SYSNODESNUM;i++) if((ntmp->ntm_sysvn[i]) && (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY); /* Dereference all system vnodes */ for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); /* vflush system vnodes */ error = vflush(mp,NULLVP,flags); if (error) { panic("ntfs_unmount: vflush failed(sysnodes): %d\n",error); } /* Check if the type of device node isn't VBAD before * touching v_specinfo. If the device vnode is revoked, the * field is NULL and touching it causes null pointer derefercence. */ if (ntmp->ntm_devvp->v_type != VBAD) spec_node_setmountedfs(ntmp->ntm_devvp, NULL); error = vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, l, 0, 0); KASSERT(error == 0); /* lock the device vnode before calling VOP_CLOSE() */ vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); KASSERT(error == 0); VOP_UNLOCK(ntmp->ntm_devvp); vrele(ntmp->ntm_devvp); /* free the toupper table, if this has been last mounted ntfs volume */ ntfs_toupper_unuse(); dprintf(("ntfs_umount: freeing memory...\n")); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; free(ntmp->ntm_ad, M_NTFSMNT); free(ntmp, M_NTFSMNT); return (0); }
/* * mp - path - addr in user space of mount point (ie /usr or whatever) * data - addr in user space of mount params including the name of the block * special file to treat as a filesystem. */ static int msdosfs_mount(struct mount *mp) { struct vnode *devvp; /* vnode for blk device to mount */ struct thread *td; /* msdosfs specific mount control block */ struct msdosfsmount *pmp = NULL; struct nameidata ndp; int error, flags; accmode_t accmode; char *from; td = curthread; if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) return (EINVAL); /* * 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) { pmp = VFSTOMSDOSFS(mp); if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { /* * Forbid export requests if filesystem has * MSDOSFS_LARGEFS flag set. */ if ((pmp->pm_flags & MSDOSFS_LARGEFS) != 0) { vfs_mount_error(mp, "MSDOSFS_LARGEFS flag set, cannot export"); return (EOPNOTSUPP); } } if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { error = VFS_SYNC(mp, MNT_WAIT); if (error) return (error); flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, 0, flags, td); if (error) return (error); /* * Now the volume is clean. Mark it so while the * device is still rw. */ error = markvoldirty(pmp, 0); if (error) { (void)markvoldirty(pmp, 1); return (error); } /* Downgrade the device from rw to ro. */ DROP_GIANT(); g_topology_lock(); error = g_access(pmp->pm_cp, 0, -1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) { (void)markvoldirty(pmp, 1); return (error); } /* * Backing out after an error was painful in the * above. Now we are committed to succeeding. */ pmp->pm_fmod = 0; pmp->pm_flags |= MSDOSFSMNT_RONLY; MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; MNT_IUNLOCK(mp); } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ devvp = pmp->pm_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_ACCESS(devvp, VREAD | VWRITE, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { VOP_UNLOCK(devvp, 0); return (error); } VOP_UNLOCK(devvp, 0); DROP_GIANT(); g_topology_lock(); error = g_access(pmp->pm_cp, 0, 1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) return (error); pmp->pm_fmod = 1; pmp->pm_flags &= ~MSDOSFSMNT_RONLY; MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_RDONLY; MNT_IUNLOCK(mp); /* Now that the volume is modifiable, mark it dirty. */ error = markvoldirty(pmp, 1); if (error) return (error); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible disk device. */ if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) return (EINVAL); NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); error = namei(&ndp); if (error) return (error); devvp = ndp.ni_vp; NDFREE(&ndp, NDF_ONLY_PNBUF); if (!vn_isdisk(devvp, &error)) { vput(devvp); return (error); } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ accmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accmode |= VWRITE; error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { vput(devvp); return (error); } if ((mp->mnt_flag & MNT_UPDATE) == 0) { error = mountmsdosfs(devvp, mp); #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ pmp = VFSTOMSDOSFS(mp); #endif } else { vput(devvp); if (devvp != pmp->pm_devvp) return (EINVAL); /* XXX needs translation */ } if (error) { vrele(devvp); return (error); } error = update_mp(mp, td); if (error) { if ((mp->mnt_flag & MNT_UPDATE) == 0) msdosfs_unmount(mp, MNT_FORCE); return error; } if (devvp->v_type == VCHR && devvp->v_rdev != NULL) devvp->v_rdev->si_mountpt = mp; vfs_mountedfrom(mp, from); #ifdef MSDOSFS_DEBUG printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); #endif return (0); }
/* * Unmount the filesystem described by mp. */ static int msdosfs_unmount(struct mount *mp, int mntflags) { struct msdosfsmount *pmp; int error, flags; error = flags = 0; pmp = VFSTOMSDOSFS(mp); if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) error = msdosfs_sync(mp, MNT_WAIT); if ((mntflags & MNT_FORCE) != 0) flags |= FORCECLOSE; else if (error != 0) return (error); error = vflush(mp, 0, flags, curthread); if (error != 0 && error != ENXIO) return (error); if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) { error = markvoldirty(pmp, 0); if (error && error != ENXIO) { (void)markvoldirty(pmp, 1); return (error); } } if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { if (pmp->pm_w2u) msdosfs_iconv->close(pmp->pm_w2u); if (pmp->pm_u2w) msdosfs_iconv->close(pmp->pm_u2w); if (pmp->pm_d2u) msdosfs_iconv->close(pmp->pm_d2u); if (pmp->pm_u2d) msdosfs_iconv->close(pmp->pm_u2d); } #ifdef MSDOSFS_DEBUG { struct vnode *vp = pmp->pm_devvp; struct bufobj *bo; bo = &vp->v_bufobj; BO_LOCK(bo); VI_LOCK(vp); vn_printf(vp, "msdosfs_umount(): just before calling VOP_CLOSE()\n"); printf("freef %p, freeb %p, mount %p\n", TAILQ_NEXT(vp, v_actfreelist), vp->v_actfreelist.tqe_prev, vp->v_mount); printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), vp->v_bufobj.bo_numoutput, vp->v_type); VI_UNLOCK(vp); BO_UNLOCK(bo); } #endif DROP_GIANT(); if (pmp->pm_devvp->v_type == VCHR && pmp->pm_devvp->v_rdev != NULL) pmp->pm_devvp->v_rdev->si_mountpt = NULL; g_topology_lock(); g_vfs_close(pmp->pm_cp); g_topology_unlock(); PICKUP_GIANT(); vrele(pmp->pm_devvp); dev_rel(pmp->pm_dev); free(pmp->pm_inusemap, M_MSDOSFSFAT); if (pmp->pm_flags & MSDOSFS_LARGEFS) msdosfs_fileno_free(mp); lockdestroy(&pmp->pm_fatlock); free(pmp, M_MSDOSFSMNT); mp->mnt_data = NULL; MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_LOCAL; MNT_IUNLOCK(mp); return (error); }
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); }
static errno_t fuse_vfsop_unmount(mount_t mp, int mntflags, vfs_context_t context) { int err = 0; int flags = 0; fuse_device_t fdev; struct fuse_data *data; struct fuse_dispatcher fdi; vnode_t fuse_rootvp = NULLVP; fuse_trace_printf_vfsop(); if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } data = fuse_get_mpdata(mp); if (!data) { panic("fuse4x: no mount private data in vfs_unmount"); } #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fdev = data->fdev; if (fdata_dead_get(data)) { /* * If the file system daemon is dead, it's pointless to try to do * any unmount-time operations that go out to user space. Therefore, * we pretend that this is a force unmount. However, this isn't of much * use. That's because if any non-root vnode is in use, the vflush() * that the kernel does before calling our VFS_UNMOUNT will fail * if the original unmount wasn't forcible already. That earlier * vflush is called with SKIPROOT though, so it wouldn't bail out * on the root vnode being in use. * * If we want, we could set FORCECLOSE here so that a non-forced * unmount will be "upgraded" to a forced unmount if the root vnode * is busy (you are cd'd to the mount point, for example). It's not * quite pure to do that though. * * flags |= FORCECLOSE; * log("fuse4x: forcing unmount on a dead file system\n"); */ } else if (!(data->dataflags & FSESS_INITED)) { flags |= FORCECLOSE; log("fuse4x: forcing unmount on not-yet-alive file system\n"); fdata_set_dead(data); } fuse_rootvp = data->rootvp; fuse_trace_printf("%s: Calling vflush(mp, fuse_rootvp, flags=0x%X);\n", __FUNCTION__, flags); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif err = vflush(mp, fuse_rootvp, flags); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fuse_trace_printf("%s: Done.\n", __FUNCTION__); if (err) { #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif return err; } if (vnode_isinuse(fuse_rootvp, 1) && !(flags & FORCECLOSE)) { #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif return EBUSY; } if (fdata_dead_get(data)) { goto alreadydead; } fdisp_init(&fdi, 0 /* no data to send along */); fdisp_make(&fdi, FUSE_DESTROY, mp, FUSE_ROOT_ID, context); fuse_trace_printf("%s: Waiting for reply from FUSE_DESTROY.\n", __FUNCTION__); err = fdisp_wait_answ(&fdi); fuse_trace_printf("%s: Reply received.\n", __FUNCTION__); if (!err) { fuse_ticket_drop(fdi.tick); } /* * Note that dounmount() signals a VQ_UNMOUNT VFS event. */ fdata_set_dead(data); alreadydead: fuse_trace_printf("%s: Calling vnode_rele(fuse_rootp);\n", __FUNCTION__); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif vnode_rele(fuse_rootvp); /* We got this reference in fuse_vfsop_mount(). */ #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fuse_trace_printf("%s: Done.\n", __FUNCTION__); data->rootvp = NULLVP; fuse_trace_printf("%s: Calling vflush(mp, NULLVP, FORCECLOSE);\n", __FUNCTION__); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif (void)vflush(mp, NULLVP, FORCECLOSE); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fuse_trace_printf("%s: Done.\n", __FUNCTION__); fuse_lck_mtx_lock(fdev->mtx); vfs_setfsprivate(mp, NULL); data->dataflags &= ~FSESS_MOUNTED; OSAddAtomic(-1, (SInt32 *)&fuse_mount_count); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif if (!(data->dataflags & FSESS_OPENED)) { /* fdev->data was left for us to clean up */ fuse_device_close_final(fdev); /* fdev->data is gone now */ } fuse_lck_mtx_unlock(fdev->mtx); return 0; }
static int chfs_unmount(struct mount *mp, int mntflags) { int flags = 0, i = 0; struct ufsmount *ump; struct chfs_mount *chmp; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; dbg("[START]\n"); ump = VFSTOUFS(mp); chmp = ump->um_chfs; /* Stop GC. */ chfs_gc_thread_stop(chmp); /* Flush everyt buffer. */ (void)vflush(mp, NULLVP, flags); if (chmp->chm_wbuf_len) { mutex_enter(&chmp->chm_lock_mountfields); chfs_flush_pending_wbuf(chmp); mutex_exit(&chmp->chm_lock_mountfields); } /* Free node references. */ for (i = 0; i < chmp->chm_ebh->peb_nr; i++) { chfs_free_node_refs(&chmp->chm_blocks[i]); } /* Destroy vnode cache hashtable. */ chfs_vnocache_hash_destroy(chmp->chm_vnocache_hash); /* Close eraseblock handler. */ ebh_close(chmp->chm_ebh); /* Destroy mutexes. */ rw_destroy(&chmp->chm_lock_wbuf); mutex_destroy(&chmp->chm_lock_vnocache); mutex_destroy(&chmp->chm_lock_sizes); mutex_destroy(&chmp->chm_lock_mountfields); /* Unmount UFS. */ if (ump->um_devvp->v_type != VBAD) { spec_node_setmountedfs(ump->um_devvp, NULL); } vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_CLOSE(ump->um_devvp, FREAD|FWRITE, NOCRED); vput(ump->um_devvp); mutex_destroy(&ump->um_lock); /* Everything done. */ kmem_free(ump, sizeof(struct ufsmount)); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; dbg("[END]\n"); return (0); }
/* * mp - path - addr in user space of mount point (ie /usr or whatever) * data - addr in user space of mount params including the name of the block * special file to treat as a filesystem. */ int msdosfs_mount(struct mount *mp, const char *path, void *data, struct nameidata *ndp, struct proc *p) { struct vnode *devvp; /* vnode for blk device to mount */ struct msdosfs_args args; /* will hold data from mount request */ /* msdosfs specific mount control block */ struct msdosfsmount *pmp = NULL; size_t size; int error, flags; mode_t accessmode; char *fspec = NULL; error = copyin(data, &args, sizeof(struct msdosfs_args)); if (error) return (error); /* * 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) { pmp = VFSTOMSDOSFS(mp); error = 0; if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, NULLVP, flags); } if (!error && (mp->mnt_flag & MNT_RELOAD)) /* not yet implemented */ error = EOPNOTSUPP; if (error) return (error); if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (suser(p, 0) != 0) { devvp = pmp->pm_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) return (error); } pmp->pm_flags &= ~MSDOSFSMNT_RONLY; } if (args.fspec == 0) { #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ if (args.flags & MSDOSFSMNT_MNTOPT) { pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; } #endif /* * Process export requests. */ return (vfs_export(mp, &pmp->pm_export, &args.export_info)); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ fspec = malloc(MNAMELEN, M_MOUNT, M_WAITOK); error = copyinstr(args.fspec, fspec, MNAMELEN - 1, &size); if (error) goto error; disk_map(fspec, fspec, MNAMELEN, DM_OPENBLCK); NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, p); if ((error = namei(ndp)) != 0) goto error; devvp = ndp->ni_vp; if (devvp->v_type != VBLK) { error = ENOTBLK; goto error_devvp; } if (major(devvp->v_rdev) >= nblkdev) { error = ENXIO; goto error_devvp; } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ if (suser(p, 0) != 0) { accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) goto error_devvp; } if ((mp->mnt_flag & MNT_UPDATE) == 0) error = msdosfs_mountfs(devvp, mp, p, &args); else { if (devvp != pmp->pm_devvp) error = EINVAL; /* XXX needs translation */ else vrele(devvp); } if (error) goto error_devvp; pmp = VFSTOMSDOSFS(mp); pmp->pm_gid = args.gid; pmp->pm_uid = args.uid; pmp->pm_mask = args.mask; pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; else if (!(pmp->pm_flags & (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { struct vnode *rvp; /* * Try to divine whether to support Win'95 long filenames */ if (FAT32(pmp)) pmp->pm_flags |= MSDOSFSMNT_LONGNAME; else { if ((error = msdosfs_root(mp, &rvp)) != 0) { msdosfs_unmount(mp, MNT_FORCE, p); goto error; } pmp->pm_flags |= findwin95(VTODE(rvp)) ? MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME; vput(rvp); } } (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); size = strlcpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN - 1); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); bcopy(&args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(args)); #ifdef MSDOSFS_DEBUG printf("msdosfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap); #endif return (0); error_devvp: vrele(devvp); error: if (fspec) free(fspec, M_MOUNT); return (error); }
/* * Unmount system call */ static int reiserfs_unmount(struct mount *mp, int mntflags) { int error, flags = 0; struct reiserfs_mount *rmp; struct reiserfs_sb_info *sbi; reiserfs_log(LOG_DEBUG, "get private data\n"); rmp = VFSTOREISERFS(mp); sbi = rmp->rm_reiserfs; /* Flangs handling */ reiserfs_log(LOG_DEBUG, "handle mntflags\n"); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; /* Flush files -> vflush */ reiserfs_log(LOG_DEBUG, "flush vnodes\n"); if ((error = vflush(mp, 0, flags, curthread))) return (error); /* XXX Super block update */ if (sbi) { if (SB_AP_BITMAP(sbi)) { int i; reiserfs_log(LOG_DEBUG, "release bitmap buffers (total: %d)\n", SB_BMAP_NR(sbi)); for (i = 0; i < SB_BMAP_NR(sbi); i++) { if (SB_AP_BITMAP(sbi)[i].bp_data) { free(SB_AP_BITMAP(sbi)[i].bp_data, M_REISERFSMNT); SB_AP_BITMAP(sbi)[i].bp_data = NULL; } } reiserfs_log(LOG_DEBUG, "free bitmaps structure\n"); free(SB_AP_BITMAP(sbi), M_REISERFSMNT); SB_AP_BITMAP(sbi) = NULL; } if (sbi->s_rs) { reiserfs_log(LOG_DEBUG, "free super block data\n"); free(sbi->s_rs, M_REISERFSMNT); sbi->s_rs = NULL; } } reiserfs_log(LOG_DEBUG, "close device\n"); #if defined(si_mountpoint) rmp->rm_devvp->v_rdev->si_mountpoint = NULL; #endif DROP_GIANT(); g_topology_lock(); g_vfs_close(rmp->rm_cp); g_topology_unlock(); PICKUP_GIANT(); vrele(rmp->rm_devvp); dev_rel(rmp->rm_dev); if (sbi) { reiserfs_log(LOG_DEBUG, "free sbi\n"); free(sbi, M_REISERFSMNT); sbi = rmp->rm_reiserfs = NULL; } if (rmp) { reiserfs_log(LOG_DEBUG, "free rmp\n"); free(rmp, M_REISERFSMNT); rmp = NULL; } mp->mnt_data = 0; MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_LOCAL; MNT_IUNLOCK(mp); reiserfs_log(LOG_DEBUG, "done\n"); return (error); }
/* * Free reference to union layer */ int union_unmount(struct mount *mp, int mntflags) { struct union_mount *um = MOUNTTOUNIONMOUNT(mp); int freeing; int error; #ifdef UNION_DIAGNOSTIC printf("union_unmount(mp = %p)\n", mp); #endif /* * Keep flushing vnodes from the mount list. * This is needed because of the un_pvp held * reference to the parent vnode. * If more vnodes have been freed on a given pass, * the try again. The loop will iterate at most * (d) times, where (d) is the maximum tree depth * in the filesystem. */ for (freeing = 0; (error = vflush(mp, NULL, 0)) != 0;) { struct vnode *vp; int n; /* count #vnodes held on mount list */ n = 0; TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) n++; /* if this is unchanged then stop */ if (n == freeing) break; /* otherwise try once more time */ freeing = n; } /* * Ok, now that we've tried doing it gently, get out the hammer. */ if (mntflags & MNT_FORCE) error = vflush(mp, NULL, FORCECLOSE); if (error) return error; /* * Discard references to upper and lower target vnodes. */ if (um->um_lowervp) vrele(um->um_lowervp); vrele(um->um_uppervp); kauth_cred_free(um->um_cred); /* * Finally, throw away the union_mount structure */ kmem_free(um, sizeof(struct union_mount)); mp->mnt_data = NULL; return 0; }
/* * Free reference to null layer */ static int nullfs_unmount(struct mount * mp, int mntflags, __unused vfs_context_t ctx) { struct null_mount * mntdata; struct vnode * vp; int error, flags; NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); /* check entitlement or superuser*/ if (!IOTaskHasEntitlement(current_task(), NULLFS_ENTITLEMENT) && vfs_context_suser(ctx) != 0) { return EPERM; } if (mntflags & MNT_FORCE) { flags = FORCECLOSE; } else { flags = 0; } mntdata = MOUNTTONULLMOUNT(mp); vp = mntdata->nullm_rootvp; // release our reference on the root before flushing. // it will get pulled out of the mount structure by reclaim vnode_getalways(vp); error = vflush(mp, vp, flags); if (error) { vnode_put(vp); return (error); } if (vnode_isinuse(vp,1) && flags == 0) { vnode_put(vp); return EBUSY; } vnode_rele(vp); // Drop reference taken by nullfs_mount vnode_put(vp); // Drop ref taken above //Force close to get rid of the last vnode (void)vflush(mp, NULL, FORCECLOSE); /* no more vnodes, so tear down the mountpoint */ lck_mtx_lock(&mntdata->nullm_lock); vfs_setfsprivate(mp, NULL); vnode_getalways(mntdata->nullm_lowerrootvp); vnode_rele(mntdata->nullm_lowerrootvp); vnode_put(mntdata->nullm_lowerrootvp); lck_mtx_unlock(&mntdata->nullm_lock); nullfs_destroy_lck(&mntdata->nullm_lock); FREE(mntdata, M_TEMP); uint64_t vflags = vfs_flags(mp); vfs_setflags(mp, vflags & ~MNT_LOCAL); return (0); }