X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzfs_vfsops.c;h=14411b8c4cfa95bce4501e95cb1f35a03f4437fd;hb=b516a07b997a8c3006788963f6b6128e505cf56c;hp=2612dfe3b10ec62d197b9041e4df85a627a3beef;hpb=4b3f12ecd5a641b182609d7fe78313d53f6e8976;p=zfs.git diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c index 2612dfe..14411b8 100644 --- a/module/zfs/zfs_vfsops.c +++ b/module/zfs/zfs_vfsops.c @@ -66,44 +66,6 @@ #include "zfs_comutil.h" #ifdef HAVE_ZPL -int zfsfstype; -static major_t zfs_major; -static minor_t zfs_minor; -static kmutex_t zfs_dev_mtx; - -extern int sys_shutdown; - -static int zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr); -static int zfs_mountroot(vfs_t *vfsp, enum whymountroot); -static void zfs_freevfs(vfs_t *vfsp); - -/* - * We need to keep a count of active fs's. - * This is necessary to prevent our module - * from being unloaded after a umount -f - */ -static uint32_t zfs_active_fs_count = 0; - -static char *noatime_cancel[] = { MNTOPT_ATIME, NULL }; -static char *atime_cancel[] = { MNTOPT_NOATIME, NULL }; -static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; -static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; - -/* - * MO_DEFAULT is not used since the default value is determined - * by the equivalent property. - */ -static mntopt_t mntopts[] = { - { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, NULL }, - { MNTOPT_XATTR, xattr_cancel, NULL, 0, NULL }, - { MNTOPT_NOATIME, noatime_cancel, NULL, 0, NULL }, - { MNTOPT_ATIME, atime_cancel, NULL, 0, NULL } -}; - -static mntopts_t zfs_mntopts = { - sizeof (mntopts) / sizeof (mntopt_t), - mntopts -}; /*ARGSUSED*/ int @@ -113,16 +75,7 @@ zfs_sync(vfs_t *vfsp, short flag, cred_t *cr) * Data integrity is job one. We don't want a compromised kernel * writing to the storage pool, so we never sync during panic. */ - if (panicstr) - return (0); - - /* - * SYNC_ATTR is used by fsflush() to force old filesystems like UFS - * to sync metadata, which they would otherwise cache indefinitely. - * Semantically, the only requirement is that the sync be initiated. - * The DMU syncs out txgs frequently, so there's nothing to do. - */ - if (flag & SYNC_ATTR) + if (unlikely(oops_in_progress)) return (0); if (vfsp != NULL) { @@ -135,14 +88,19 @@ zfs_sync(vfs_t *vfsp, short flag, cred_t *cr) ZFS_ENTER(zfsvfs); dp = dmu_objset_pool(zfsvfs->z_os); +#ifdef HAVE_SHUTDOWN /* * If the system is shutting down, then skip any * filesystems which may exist on a suspended pool. + * + * XXX: This can be implemented using the Linux reboot + * notifiers: {un}register_reboot_notifier(). */ if (sys_shutdown && spa_suspended(dp->dp_spa)) { ZFS_EXIT(zfsvfs); return (0); } +#endif /* HAVE_SHUTDOWN */ if (zfsvfs->z_log != NULL) zil_commit(zfsvfs->z_log, 0); @@ -161,58 +119,6 @@ zfs_sync(vfs_t *vfsp, short flag, cred_t *cr) } EXPORT_SYMBOL(zfs_sync); -static int -zfs_create_unique_device(dev_t *dev) -{ - major_t new_major; - - do { - ASSERT3U(zfs_minor, <=, MAXMIN32); - minor_t start = zfs_minor; - do { - mutex_enter(&zfs_dev_mtx); - if (zfs_minor >= MAXMIN32) { - /* - * If we're still using the real major - * keep out of /dev/zfs and /dev/zvol minor - * number space. If we're using a getudev()'ed - * major number, we can use all of its minors. - */ - if (zfs_major == ddi_name_to_major(ZFS_DRIVER)) - zfs_minor = ZFS_MIN_MINOR; - else - zfs_minor = 0; - } else { - zfs_minor++; - } - *dev = makedevice(zfs_major, zfs_minor); - mutex_exit(&zfs_dev_mtx); - } while (vfs_devismounted(*dev) && zfs_minor != start); - if (zfs_minor == start) { - /* - * We are using all ~262,000 minor numbers for the - * current major number. Create a new major number. - */ - if ((new_major = getudev()) == (major_t)-1) { - cmn_err(CE_WARN, - "zfs_mount: Can't get unique major " - "device number."); - return (-1); - } - mutex_enter(&zfs_dev_mtx); - zfs_major = new_major; - zfs_minor = 0; - - mutex_exit(&zfs_dev_mtx); - } else { - break; - } - /* CONSTANTCONDITION */ - } while (1); - - return (0); -} - static void atime_changed_cb(void *arg, uint64_t newval) { @@ -1072,6 +978,7 @@ zfsvfs_free(zfsvfs_t *zfsvfs) kmem_free(zfsvfs, sizeof (zfsvfs_t)); } +#ifdef HAVE_FUID_FEATURES static void zfs_set_fuid_feature(zfsvfs_t *zfsvfs) { @@ -1086,11 +993,11 @@ zfs_set_fuid_feature(zfsvfs_t *zfsvfs) } zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os); } +#endif /* HAVE_FUID_FEATURES */ int zfs_domount(vfs_t *vfsp, char *osname) { - dev_t mount_dev; uint64_t recordsize, fsid_guid; int error = 0; zfsvfs_t *zfsvfs; @@ -1107,18 +1014,10 @@ zfs_domount(vfs_t *vfsp, char *osname) vfsp->vfs_bcount = 0; vfsp->vfs_data = NULL; - if (zfs_create_unique_device(&mount_dev) == -1) { - error = ENODEV; - goto out; - } - ASSERT(vfs_devismounted(mount_dev) == 0); - if ((error = dsl_prop_get_integer(osname, "recordsize", &recordsize, NULL))) goto out; - vfsp->vfs_dev = mount_dev; - vfsp->vfs_fstype = zfsfstype; vfsp->vfs_bsize = recordsize; vfsp->vfs_flag |= VFS_NOTRUNC; vfsp->vfs_data = zfsvfs; @@ -1134,9 +1033,9 @@ zfs_domount(vfs_t *vfsp, char *osname) fsid_guid = dmu_objset_fsid_guid(zfsvfs->z_os); ASSERT((fsid_guid & ~((1ULL<<56)-1)) == 0); vfsp->vfs_fsid.val[0] = fsid_guid; - vfsp->vfs_fsid.val[1] = ((fsid_guid>>32) << 8) | - zfsfstype & 0xFF; + vfsp->vfs_fsid.val[1] = ((fsid_guid>>32) << 8); +#ifdef HAVE_FUID_FEATURES /* * Set features for file system. */ @@ -1150,6 +1049,7 @@ zfs_domount(vfs_t *vfsp, char *osname) vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); } vfs_set_feature(vfsp, VFSFT_ZEROCOPY_SUPPORTED); +#endif /* HAVE_FUID_FEATURES */ if (dmu_objset_is_snapshot(zfsvfs->z_os)) { uint64_t pval; @@ -1175,8 +1075,6 @@ out: if (error) { dmu_objset_disown(zfsvfs->z_os, zfsvfs); zfsvfs_free(zfsvfs); - } else { - atomic_add_32(&zfs_active_fs_count, 1); } return (error); @@ -1257,326 +1155,6 @@ zfs_check_global_label(const char *dsname, const char *hexsl) } #endif /* HAVE_MLSLABEL */ -/* - * zfs_mount_label_policy: - * Determine whether the mount is allowed according to MAC check. - * by comparing (where appropriate) label of the dataset against - * the label of the zone being mounted into. If the dataset has - * no label, create one. - * - * Returns: - * 0 : access allowed - * >0 : error code, such as EACCES - */ -static int -zfs_mount_label_policy(vfs_t *vfsp, char *osname) -{ - int error, retv; - zone_t *mntzone = NULL; - ts_label_t *mnt_tsl; - bslabel_t *mnt_sl; - bslabel_t ds_sl; - char ds_hexsl[MAXNAMELEN]; - - retv = EACCES; /* assume the worst */ - - /* - * Start by getting the dataset label if it exists. - */ - error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL), - 1, sizeof (ds_hexsl), &ds_hexsl, NULL); - if (error) - return (EACCES); - - /* - * If labeling is NOT enabled, then disallow the mount of datasets - * which have a non-default label already. No other label checks - * are needed. - */ - if (!is_system_labeled()) { - if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) - return (0); - return (EACCES); - } - - /* - * Get the label of the mountpoint. If mounting into the global - * zone (i.e. mountpoint is not within an active zone and the - * zoned property is off), the label must be default or - * admin_low/admin_high only; no other checks are needed. - */ - mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); - if (mntzone->zone_id == GLOBAL_ZONEID) { - uint64_t zoned; - - zone_rele(mntzone); - - if (dsl_prop_get_integer(osname, - zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) - return (EACCES); - if (!zoned) - return (zfs_check_global_label(osname, ds_hexsl)); - else - /* - * This is the case of a zone dataset being mounted - * initially, before the zone has been fully created; - * allow this mount into global zone. - */ - return (0); - } - - mnt_tsl = mntzone->zone_slabel; - ASSERT(mnt_tsl != NULL); - label_hold(mnt_tsl); - mnt_sl = label2bslabel(mnt_tsl); - - if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) { - /* - * The dataset doesn't have a real label, so fabricate one. - */ - char *str = NULL; - - if (l_to_str_internal(mnt_sl, &str) == 0 && - dsl_prop_set(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL), - ZPROP_SRC_LOCAL, 1, strlen(str) + 1, str) == 0) - retv = 0; - if (str != NULL) - kmem_free(str, strlen(str) + 1); - } else if (hexstr_to_label(ds_hexsl, &ds_sl) == 0) { - /* - * Now compare labels to complete the MAC check. If the - * labels are equal then allow access. If the mountpoint - * label dominates the dataset label, allow readonly access. - * Otherwise, access is denied. - */ - if (blequal(mnt_sl, &ds_sl)) - retv = 0; - else if (bldominates(mnt_sl, &ds_sl)) { - vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); - retv = 0; - } - } - - label_rele(mnt_tsl); - zone_rele(mntzone); - return (retv); -} - -static int -zfs_mountroot(vfs_t *vfsp, enum whymountroot why) -{ - int error = 0; - static int zfsrootdone = 0; - zfsvfs_t *zfsvfs = NULL; - znode_t *zp = NULL; - vnode_t *vp = NULL; - char *zfs_bootfs; - char *zfs_devid; - - ASSERT(vfsp); - - /* - * The filesystem that we mount as root is defined in the - * boot property "zfs-bootfs" with a format of - * "poolname/root-dataset-objnum". - */ - if (why == ROOT_INIT) { - if (zfsrootdone++) - return (EBUSY); - /* - * the process of doing a spa_load will require the - * clock to be set before we could (for example) do - * something better by looking at the timestamp on - * an uberblock, so just set it to -1. - */ - clkset(-1); - - if ((zfs_bootfs = spa_get_bootprop("zfs-bootfs")) == NULL) { - cmn_err(CE_NOTE, "spa_get_bootfs: can not get " - "bootfs name"); - return (EINVAL); - } - zfs_devid = spa_get_bootprop("diskdevid"); - error = spa_import_rootpool(rootfs.bo_name, zfs_devid); - if (zfs_devid) - spa_free_bootprop(zfs_devid); - if (error) { - spa_free_bootprop(zfs_bootfs); - cmn_err(CE_NOTE, "spa_import_rootpool: error %d", - error); - return (error); - } - if (error = zfs_parse_bootfs(zfs_bootfs, rootfs.bo_name)) { - spa_free_bootprop(zfs_bootfs); - cmn_err(CE_NOTE, "zfs_parse_bootfs: error %d", - error); - return (error); - } - - spa_free_bootprop(zfs_bootfs); - - if (error = vfs_lock(vfsp)) - return (error); - - if (error = zfs_domount(vfsp, rootfs.bo_name)) { - cmn_err(CE_NOTE, "zfs_domount: error %d", error); - goto out; - } - - zfsvfs = (zfsvfs_t *)vfsp->vfs_data; - ASSERT(zfsvfs); - if (error = zfs_zget(zfsvfs, zfsvfs->z_root, &zp)) { - cmn_err(CE_NOTE, "zfs_zget: error %d", error); - goto out; - } - - vp = ZTOV(zp); - mutex_enter(&vp->v_lock); - vp->v_flag |= VROOT; - mutex_exit(&vp->v_lock); - rootvp = vp; - - /* - * Leave rootvp held. The root file system is never unmounted. - */ - - vfs_add((struct vnode *)0, vfsp, - (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0); -out: - vfs_unlock(vfsp); - return (error); - } else if (why == ROOT_REMOUNT) { - readonly_changed_cb(vfsp->vfs_data, B_FALSE); - vfsp->vfs_flag |= VFS_REMOUNT; - - /* refresh mount options */ - zfs_unregister_callbacks(vfsp->vfs_data); - return (zfs_register_callbacks(vfsp)); - - } else if (why == ROOT_UNMOUNT) { - zfs_unregister_callbacks((zfsvfs_t *)vfsp->vfs_data); - (void) zfs_sync(vfsp, 0, 0); - return (0); - } - - /* - * if "why" is equal to anything else other than ROOT_INIT, - * ROOT_REMOUNT, or ROOT_UNMOUNT, we do not support it. - */ - return (ENOTSUP); -} - -/*ARGSUSED*/ -static int -zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) -{ - char *osname; - pathname_t spn; - int error = 0; - uio_seg_t fromspace = (uap->flags & MS_SYSSPACE) ? - UIO_SYSSPACE : UIO_USERSPACE; - int canwrite; - - if (mvp->v_type != VDIR) - return (ENOTDIR); - - mutex_enter(&mvp->v_lock); - if ((uap->flags & MS_REMOUNT) == 0 && - (uap->flags & MS_OVERLAY) == 0 && - (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { - mutex_exit(&mvp->v_lock); - return (EBUSY); - } - mutex_exit(&mvp->v_lock); - - /* - * ZFS does not support passing unparsed data in via MS_DATA. - * Users should use the MS_OPTIONSTR interface; this means - * that all option parsing is already done and the options struct - * can be interrogated. - */ - if ((uap->flags & MS_DATA) && uap->datalen > 0) - return (EINVAL); - - /* - * Get the objset name (the "special" mount argument). - */ - if ((error = pn_get(uap->spec, fromspace, &spn))) - return (error); - - osname = spn.pn_path; - - /* - * Check for mount privilege? - * - * If we don't have privilege then see if - * we have local permission to allow it - */ - error = secpolicy_fs_mount(cr, mvp, vfsp); - if (error) { - if (dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr) == 0) { - vattr_t vattr; - - /* - * Make sure user is the owner of the mount point - * or has sufficient privileges. - */ - - vattr.va_mask = AT_UID; - - if (VOP_GETATTR(mvp, &vattr, 0, cr, NULL)) { - goto out; - } - - if (secpolicy_vnode_owner(cr, vattr.va_uid) != 0 && - VOP_ACCESS(mvp, VWRITE, 0, cr, NULL) != 0) { - goto out; - } - secpolicy_fs_mount_clearopts(cr, vfsp); - } else { - goto out; - } - } - - /* - * Refuse to mount a filesystem if we are in a local zone and the - * dataset is not visible. - */ - if (!INGLOBALZONE(curproc) && - (!zone_dataset_visible(osname, &canwrite) || !canwrite)) { - error = EPERM; - goto out; - } - - error = zfs_mount_label_policy(vfsp, osname); - if (error) - goto out; - - /* - * When doing a remount, we simply refresh our temporary properties - * according to those options set in the current VFS options. - */ - if (uap->flags & MS_REMOUNT) { - /* refresh mount options */ - zfs_unregister_callbacks(vfsp->vfs_data); - error = zfs_register_callbacks(vfsp); - goto out; - } - - error = zfs_domount(vfsp, osname); - - /* - * Add an extra VFS_HOLD on our parent vfs so that it can't - * disappear due to a forced unmount. - */ - if (error == 0 && ((zfsvfs_t *)vfsp->vfs_data)->z_issnap) - VFS_HOLD(mvp->v_vfsp); - -out: - pn_free(&spn); - return (error); -} - int zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp) { @@ -1625,7 +1203,7 @@ zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp) /* * We're a zfs filesystem. */ - (void) strcpy(statp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); + (void) strcpy(statp->f_basetype, MNTTYPE_ZFS); statp->f_flag = vf_to_stf(vfsp->vfs_flag); @@ -2020,60 +1598,15 @@ zfs_freevfs(vfs_t *vfsp) { zfsvfs_t *zfsvfs = vfsp->vfs_data; - /* - * If this is a snapshot, we have an extra VFS_HOLD on our parent - * from zfs_mount(). Release it here. If we came through - * zfs_mountroot() instead, we didn't grab an extra hold, so - * skip the VFS_RELE for rootvfs. - */ - if (zfsvfs->z_issnap && (vfsp != rootvfs)) - VFS_RELE(zfsvfs->z_parent->z_vfs); - zfsvfs_free(zfsvfs); - - atomic_add_32(&zfs_active_fs_count, -1); -} - -/* - * VFS_INIT() initialization. Note that there is no VFS_FINI(), - * so we can't safely do any non-idempotent initialization here. - * Leave that to zfs_init() and zfs_fini(), which are called - * from the module's _init() and _fini() entry points. - */ -/*ARGSUSED*/ -static int -zfs_vfsinit(int fstype, char *name) -{ - int error; - - zfsfstype = fstype; - mutex_init(&zfs_dev_mtx, NULL, MUTEX_DEFAULT, NULL); - - /* - * Unique major number for all zfs mounts. - * If we run out of 32-bit minors, we'll getudev() another major. - */ - zfs_major = ddi_name_to_major(ZFS_DRIVER); - zfs_minor = ZFS_MIN_MINOR; - - return (0); } #endif /* HAVE_ZPL */ void zfs_init(void) { -#ifdef HAVE_ZPL - /* - * Initialize .zfs directory structures - */ zfsctl_init(); - - /* - * Initialize znode cache, vnode ops, etc... - */ zfs_znode_init(); -#endif /* HAVE_ZPL */ dmu_objset_register_type(DMU_OST_ZFS, zfs_space_delta_cb); } @@ -2081,10 +1614,8 @@ zfs_init(void) void zfs_fini(void) { -#ifdef HAVE_ZPL zfsctl_fini(); zfs_znode_fini(); -#endif /* HAVE_ZPL */ } #ifdef HAVE_ZPL @@ -2150,8 +1681,10 @@ zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers) zfsvfs->z_version = newvers; +#ifdef HAVE_FUID_FEATURES if (zfsvfs->z_version >= ZPL_VERSION_FUID) zfs_set_fuid_feature(zfsvfs); +#endif /* HAVE_FUID_FEATURES */ return (0); }