X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzfs_ioctl.c;h=efb6bf5e7ca7d5c4057ddc3e4d1c0c893d8044c4;hb=46e18b3f0fc13aa0859d0fef7dc829db20491ab6;hp=4e26cae201c42093cc11e9c9f82f4739cfe44086;hpb=c65aa5b2b9c48375ea1c451f252f0056e16f4e49;p=zfs.git diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 4e26cae..efb6bf5 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -58,27 +58,27 @@ #include #include #include -#include #include #include #include #include #include #include +#include + +#include #include "zfs_namecheck.h" #include "zfs_prop.h" #include "zfs_deleg.h" #include "zfs_comutil.h" -extern struct modlfs zfs_modlfs; +kmutex_t zfsdev_state_lock; +list_t zfsdev_state_list; extern void zfs_init(void); extern void zfs_fini(void); -ldi_ident_t zfs_li = NULL; -dev_info_t *zfs_dip; - typedef int zfs_ioc_func_t(zfs_cmd_t *); typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); @@ -169,7 +169,7 @@ history_str_get(zfs_cmd_t *zc) if (zc->zc_history == 0) return (NULL); - buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); + buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP | KM_NODEBUG); if (copyinstr((void *)(uintptr_t)zc->zc_history, buf, HIS_MAX_RECORD_LEN, NULL) != 0) { history_str_free(buf); @@ -384,6 +384,7 @@ zfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds, static int zfs_set_slabel_policy(const char *name, char *strval, cred_t *cr) { +#ifdef HAVE_MLSLABEL char ds_hexsl[MAXNAMELEN]; bslabel_t ds_sl, new_sl; boolean_t new_default = FALSE; @@ -431,7 +432,7 @@ zfs_set_slabel_policy(const char *name, char *strval, cred_t *cr) /* * If the existing dataset label is nondefault, check if the * dataset is mounted (label cannot be changed while mounted). - * Get the zfsvfs; if there isn't one, then the dataset isn't + * Get the zfs_sb_t; if there isn't one, then the dataset isn't * mounted (or isn't a dataset, doesn't exist, ...). */ if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) { @@ -471,6 +472,9 @@ out_check: if (needed_priv != -1) return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL)); return (0); +#else + return ENOTSUP; +#endif /* HAVE_MLSLABEL */ } static int @@ -587,6 +591,7 @@ zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) return (error); } +#ifdef HAVE_SHARE static int zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) { @@ -610,10 +615,12 @@ zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) return (dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_SHARE, cr)); } +#endif /* HAVE_SHARE */ int zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) { +#ifdef HAVE_SHARE if (!INGLOBALZONE(curproc)) return (EPERM); @@ -622,11 +629,15 @@ zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) } else { return (zfs_secpolicy_deleg_share(zc, cr)); } +#else + return (ENOTSUP); +#endif /* HAVE_SHARE */ } int zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) { +#ifdef HAVE_SHARE if (!INGLOBALZONE(curproc)) return (EPERM); @@ -635,6 +646,9 @@ zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) } else { return (zfs_secpolicy_deleg_share(zc, cr)); } +#else + return (ENOTSUP); +#endif /* HAVE_SHARE */ } static int @@ -835,18 +849,6 @@ zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) return (error); } -static int -zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) -{ - int error; - - error = secpolicy_fs_unmount(cr, NULL); - if (error) { - error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); - } - return (error); -} - /* * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires * SYS_CONFIG privilege, which is not available in a local zone. @@ -1010,7 +1012,7 @@ get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) if (size == 0) return (EINVAL); - packed = kmem_alloc(size, KM_SLEEP); + packed = kmem_alloc(size, KM_SLEEP | KM_NODEBUG); if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, iflag)) != 0) { @@ -1076,7 +1078,7 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) if (size > zc->zc_nvlist_dst_size) { error = ENOMEM; } else { - packed = kmem_alloc(size, KM_SLEEP); + packed = kmem_alloc(size, KM_SLEEP | KM_NODEBUG); VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, KM_SLEEP) == 0); if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, @@ -1090,7 +1092,7 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) } static int -getzfsvfs(const char *dsname, zfsvfs_t **zfvp) +get_zfs_sb(const char *dsname, zfs_sb_t **zsbp) { objset_t *os; int error; @@ -1104,9 +1106,10 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp) } mutex_enter(&os->os_user_ptr_lock); - *zfvp = dmu_objset_get_user(os); - if (*zfvp) { - VFS_HOLD((*zfvp)->z_vfs); + *zsbp = dmu_objset_get_user(os); + if (*zsbp && (*zsbp)->z_sb) { + if (atomic_inc_not_zero(&((*zsbp)->z_sb->s_active))) + error = ESRCH; } else { error = ESRCH; } @@ -1116,26 +1119,26 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp) } /* - * Find a zfsvfs_t for a mounted filesystem, or create our own, in which - * case its z_vfs will be NULL, and it will be opened as the owner. + * Find a zfs_sb_t for a mounted filesystem, or create our own, in which + * case its z_sb will be NULL, and it will be opened as the owner. */ static int -zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer) +zfs_sb_hold(const char *name, void *tag, zfs_sb_t **zsbp, boolean_t writer) { int error = 0; - if (getzfsvfs(name, zfvp) != 0) - error = zfsvfs_create(name, zfvp); + if (get_zfs_sb(name, zsbp) != 0) + error = zfs_sb_create(name, zsbp); if (error == 0) { - rrw_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER : + rrw_enter(&(*zsbp)->z_teardown_lock, (writer) ? RW_WRITER : RW_READER, tag); - if ((*zfvp)->z_unmounted) { + if ((*zsbp)->z_unmounted) { /* * XXX we could probably try again, since the unmounting * thread should be just about to disassociate the * objset from the zfsvfs. */ - rrw_exit(&(*zfvp)->z_teardown_lock, tag); + rrw_exit(&(*zsbp)->z_teardown_lock, tag); return (EBUSY); } } @@ -1143,15 +1146,15 @@ zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer) } static void -zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) +zfs_sb_rele(zfs_sb_t *zsb, void *tag) { - rrw_exit(&zfsvfs->z_teardown_lock, tag); + rrw_exit(&zsb->z_teardown_lock, tag); - if (zfsvfs->z_vfs) { - VFS_RELE(zfsvfs->z_vfs); + if (zsb->z_sb) { + deactivate_super(zsb->z_sb); } else { - dmu_objset_disown(zfsvfs->z_os, zfsvfs); - zfsvfs_free(zfsvfs); + dmu_objset_disown(zsb->z_os, zsb); + zfs_sb_free(zsb); } } @@ -1267,6 +1270,9 @@ zfs_ioc_pool_import(zfs_cmd_t *zc) error = err; } + if (error == 0) + zvol_create_minors(zc->zc_name); + nvlist_free(config); if (props) @@ -1436,7 +1442,7 @@ zfs_ioc_pool_get_history(zfs_cmd_t *zc) return (ENOTSUP); } - hist_buf = kmem_alloc(size, KM_SLEEP); + hist_buf = vmem_alloc(size, KM_SLEEP); if ((error = spa_history_get(spa, &zc->zc_history_offset, &zc->zc_history_len, hist_buf)) == 0) { error = ddi_copyout(hist_buf, @@ -1445,7 +1451,7 @@ zfs_ioc_pool_get_history(zfs_cmd_t *zc) } spa_close(spa, FTAG); - kmem_free(hist_buf, size); + vmem_free(hist_buf, size); return (error); } @@ -1748,9 +1754,10 @@ zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) */ if (!zc->zc_objset_stats.dds_inconsistent) { if (dmu_objset_type(os) == DMU_OST_ZVOL) - VERIFY(zvol_get_stats(os, nv) == 0); + error = zvol_get_stats(os, nv); } - error = put_nvlist(zc, nv); + if (error == 0) + error = put_nvlist(zc, nv); nvlist_free(nv); } @@ -1797,7 +1804,7 @@ zfs_ioc_objset_stats(zfs_cmd_t *zc) * local property values. */ static int -zfs_ioc_objset_recvd_props(struct file *filp, zfs_cmd_t *zc) +zfs_ioc_objset_recvd_props(zfs_cmd_t *zc) { objset_t *os = NULL; int error; @@ -2066,7 +2073,7 @@ zfs_prop_set_userquota(const char *dsname, nvpair_t *pair) zfs_userquota_prop_t type; uint64_t rid; uint64_t quota; - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; int err; if (nvpair_type(pair) == DATA_TYPE_NVLIST) { @@ -2091,10 +2098,10 @@ zfs_prop_set_userquota(const char *dsname, nvpair_t *pair) rid = valary[1]; quota = valary[2]; - err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_FALSE); + err = zfs_sb_hold(dsname, FTAG, &zsb, B_FALSE); if (err == 0) { - err = zfs_set_userquota(zfsvfs, type, domain, rid, quota); - zfsvfs_rele(zfsvfs, FTAG); + err = zfs_set_userquota(zsb, type, domain, rid, quota); + zfs_sb_rele(zsb, FTAG); } return (err); @@ -2149,18 +2156,17 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, err = dsl_dataset_set_reservation(dsname, source, intval); break; case ZFS_PROP_VOLSIZE: - err = zvol_set_volsize(dsname, ddi_driver_major(zfs_dip), - intval); + err = zvol_set_volsize(dsname, intval); break; case ZFS_PROP_VERSION: { - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; - if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) + if ((err = zfs_sb_hold(dsname, FTAG, &zsb, B_TRUE)) != 0) break; - err = zfs_set_version(zfsvfs, intval); - zfsvfs_rele(zfsvfs, FTAG); + err = zfs_set_version(zsb, intval); + zfs_sb_rele(zsb, FTAG); if (err == 0 && intval >= ZPL_VERSION_USERSPACE) { zfs_cmd_t *zc; @@ -2622,6 +2628,30 @@ zfs_ioc_pool_get_props(zfs_cmd_t *zc) /* * inputs: + * zc_name name of volume + * + * outputs: none + */ +static int +zfs_ioc_create_minor(zfs_cmd_t *zc) +{ + return (zvol_create_minor(zc->zc_name)); +} + +/* + * inputs: + * zc_name name of volume + * + * outputs: none + */ +static int +zfs_ioc_remove_minor(zfs_cmd_t *zc) +{ + return (zvol_remove_minor(zc->zc_name)); +} + +/* + * inputs: * zc_name name of filesystem * zc_nvlist_src{_size} nvlist of delegated permissions * zc_perm_action allow/unallow flag @@ -2691,6 +2721,7 @@ zfs_ioc_get_fsacl(zfs_cmd_t *zc) return (error); } +#ifdef HAVE_SNAPSHOT /* * Search the vfs list for a specified resource. Returns a pointer to it * or NULL if no suitable entry is found. The caller of this routine @@ -2706,7 +2737,7 @@ zfs_get_vfs(const char *resource) vfsp = rootvfs; do { if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { - VFS_HOLD(vfsp); + mntget(vfsp); vfs_found = vfsp; break; } @@ -2715,6 +2746,7 @@ zfs_get_vfs(const char *resource) vfs_list_unlock(); return (vfs_found); } +#endif /* HAVE_SNAPSHOT */ /* ARGSUSED */ static void @@ -3069,6 +3101,7 @@ out: int zfs_unmount_snap(const char *name, void *arg) { +#ifdef HAVE_SNAPSHOT vfs_t *vfsp = NULL; if (arg) { @@ -3088,13 +3121,14 @@ zfs_unmount_snap(const char *name, void *arg) int err; if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { - VFS_RELE(vfsp); + mntput(vfsp); return (err); } - VFS_RELE(vfsp); + mntput(vfsp); if ((err = dounmount(vfsp, flag, kcred)) != 0) return (err); } +#endif /* HAVE_SNAPSHOT */ return (0); } @@ -3156,7 +3190,7 @@ zfs_ioc_rollback(zfs_cmd_t *zc) { dsl_dataset_t *ds, *clone; int error; - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; char *clone_name; error = dsl_dataset_hold(zc->zc_name, FTAG, &ds); @@ -3190,8 +3224,8 @@ zfs_ioc_rollback(zfs_cmd_t *zc) /* * Do clone swap. */ - if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { - error = zfs_suspend_fs(zfsvfs); + if (get_zfs_sb(zc->zc_name, &zsb) == 0) { + error = zfs_suspend_fs(zsb); if (error == 0) { int resume_err; @@ -3203,10 +3237,10 @@ zfs_ioc_rollback(zfs_cmd_t *zc) } else { error = EBUSY; } - resume_err = zfs_resume_fs(zfsvfs, zc->zc_name); + resume_err = zfs_resume_fs(zsb, zc->zc_name); error = error ? error : resume_err; } - VFS_RELE(zfsvfs->z_vfs); + deactivate_super(zsb->z_sb); } else { if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { error = dsl_dataset_clone_swap(clone, ds, B_TRUE); @@ -3241,6 +3275,7 @@ static int zfs_ioc_rename(zfs_cmd_t *zc) { boolean_t recursive = zc->zc_cookie & 1; + int err; zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || @@ -3254,13 +3289,18 @@ zfs_ioc_rename(zfs_cmd_t *zc) */ if (!recursive && strchr(zc->zc_name, '@') != NULL && zc->zc_objset_type == DMU_OST_ZFS) { - int err = zfs_unmount_snap(zc->zc_name, NULL); + err = zfs_unmount_snap(zc->zc_name, NULL); if (err) return (err); } - if (zc->zc_objset_type == DMU_OST_ZVOL) + + err = dmu_objset_rename(zc->zc_name, zc->zc_value, recursive); + if ((err == 0) && (zc->zc_objset_type == DMU_OST_ZVOL)) { (void) zvol_remove_minor(zc->zc_name); - return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); + (void) zvol_create_minor(zc->zc_value); + } + + return (err); } static int @@ -3416,7 +3456,7 @@ zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); - zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); + zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP | KM_NODEBUG); (void) strcpy(zc->zc_name, dataset); pair = nvlist_next_nvpair(props, NULL); while (pair != NULL) { @@ -3670,22 +3710,22 @@ zfs_ioc_recv(zfs_cmd_t *zc) &zc->zc_action_handle); if (error == 0) { - zfsvfs_t *zfsvfs = NULL; + zfs_sb_t *zsb = NULL; - if (getzfsvfs(tofs, &zfsvfs) == 0) { + if (get_zfs_sb(tofs, &zsb) == 0) { /* online recv */ int end_err; - error = zfs_suspend_fs(zfsvfs); + error = zfs_suspend_fs(zsb); /* * If the suspend fails, then the recv_end will * likely also fail, and clean up after itself. */ end_err = dmu_recv_end(&drc); if (error == 0) - error = zfs_resume_fs(zfsvfs, tofs); + error = zfs_resume_fs(zsb, tofs); error = error ? error : end_err; - VFS_RELE(zfsvfs->z_vfs); + deactivate_super(zsb->z_sb); } else { error = dmu_recv_end(&drc); } @@ -4012,19 +4052,19 @@ zfs_ioc_promote(zfs_cmd_t *zc) static int zfs_ioc_userspace_one(zfs_cmd_t *zc) { - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; int error; if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) return (EINVAL); - error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); + error = zfs_sb_hold(zc->zc_name, FTAG, &zsb, B_FALSE); if (error) return (error); - error = zfs_userspace_one(zfsvfs, + error = zfs_userspace_one(zsb, zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); - zfsvfs_rele(zfsvfs, FTAG); + zfs_sb_rele(zsb, FTAG); return (error); } @@ -4043,19 +4083,21 @@ zfs_ioc_userspace_one(zfs_cmd_t *zc) static int zfs_ioc_userspace_many(zfs_cmd_t *zc) { - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; int bufsize = zc->zc_nvlist_dst_size; + int error; + void *buf; if (bufsize <= 0) return (ENOMEM); - int error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); + error = zfs_sb_hold(zc->zc_name, FTAG, &zsb, B_FALSE); if (error) return (error); - void *buf = kmem_alloc(bufsize, KM_SLEEP); + buf = vmem_alloc(bufsize, KM_SLEEP); - error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, + error = zfs_userspace_many(zsb, zc->zc_objset_type, &zc->zc_cookie, buf, &zc->zc_nvlist_dst_size); if (error == 0) { @@ -4063,8 +4105,8 @@ zfs_ioc_userspace_many(zfs_cmd_t *zc) (void *)(uintptr_t)zc->zc_nvlist_dst, zc->zc_nvlist_dst_size); } - kmem_free(buf, bufsize); - zfsvfs_rele(zfsvfs, FTAG); + vmem_free(buf, bufsize); + zfs_sb_rele(zsb, FTAG); return (error); } @@ -4081,22 +4123,22 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) { objset_t *os; int error = 0; - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; - if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { - if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { + if (get_zfs_sb(zc->zc_name, &zsb) == 0) { + if (!dmu_objset_userused_enabled(zsb->z_os)) { /* * If userused is not enabled, it may be because the * objset needs to be closed & reopened (to grow the * objset_phys_t). Suspend/resume the fs will do that. */ - error = zfs_suspend_fs(zfsvfs); + error = zfs_suspend_fs(zsb); if (error == 0) - error = zfs_resume_fs(zfsvfs, zc->zc_name); + error = zfs_resume_fs(zsb, zc->zc_name); } if (error == 0) - error = dmu_objset_userspace_upgrade(zfsvfs->z_os); - VFS_RELE(zfsvfs->z_vfs); + error = dmu_objset_userspace_upgrade(zsb->z_os); + deactivate_super(zsb->z_sb); } else { /* XXX kind of reading contents without owning */ error = dmu_objset_hold(zc->zc_name, FTAG, &os); @@ -4110,138 +4152,10 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) return (error); } -/* - * We don't want to have a hard dependency - * against some special symbols in sharefs - * nfs, and smbsrv. Determine them if needed when - * the first file system is shared. - * Neither sharefs, nfs or smbsrv are unloadable modules. - */ -int (*znfsexport_fs)(void *arg); -int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); -int (*zsmbexport_fs)(void *arg, boolean_t add_share); - -int zfs_nfsshare_inited; -int zfs_smbshare_inited; - -ddi_modhandle_t nfs_mod; -ddi_modhandle_t sharefs_mod; -ddi_modhandle_t smbsrv_mod; -kmutex_t zfs_share_lock; - -static int -zfs_init_sharefs() -{ - int error; - - ASSERT(MUTEX_HELD(&zfs_share_lock)); - /* Both NFS and SMB shares also require sharetab support. */ - if (sharefs_mod == NULL && ((sharefs_mod = - ddi_modopen("fs/sharefs", - KRTLD_MODE_FIRST, &error)) == NULL)) { - return (ENOSYS); - } - if (zshare_fs == NULL && ((zshare_fs = - (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) - ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { - return (ENOSYS); - } - return (0); -} - static int zfs_ioc_share(zfs_cmd_t *zc) { - int error; - int opcode; - - switch (zc->zc_share.z_sharetype) { - case ZFS_SHARE_NFS: - case ZFS_UNSHARE_NFS: - if (zfs_nfsshare_inited == 0) { - mutex_enter(&zfs_share_lock); - if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", - KRTLD_MODE_FIRST, &error)) == NULL)) { - mutex_exit(&zfs_share_lock); - return (ENOSYS); - } - if (znfsexport_fs == NULL && - ((znfsexport_fs = (int (*)(void *)) - ddi_modsym(nfs_mod, - "nfs_export", &error)) == NULL)) { - mutex_exit(&zfs_share_lock); - return (ENOSYS); - } - error = zfs_init_sharefs(); - if (error) { - mutex_exit(&zfs_share_lock); - return (ENOSYS); - } - zfs_nfsshare_inited = 1; - mutex_exit(&zfs_share_lock); - } - break; - case ZFS_SHARE_SMB: - case ZFS_UNSHARE_SMB: - if (zfs_smbshare_inited == 0) { - mutex_enter(&zfs_share_lock); - if (smbsrv_mod == NULL && ((smbsrv_mod = - ddi_modopen("drv/smbsrv", - KRTLD_MODE_FIRST, &error)) == NULL)) { - mutex_exit(&zfs_share_lock); - return (ENOSYS); - } - if (zsmbexport_fs == NULL && ((zsmbexport_fs = - (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, - "smb_server_share", &error)) == NULL)) { - mutex_exit(&zfs_share_lock); - return (ENOSYS); - } - error = zfs_init_sharefs(); - if (error) { - mutex_exit(&zfs_share_lock); - return (ENOSYS); - } - zfs_smbshare_inited = 1; - mutex_exit(&zfs_share_lock); - } - break; - default: - return (EINVAL); - } - - switch (zc->zc_share.z_sharetype) { - case ZFS_SHARE_NFS: - case ZFS_UNSHARE_NFS: - if (error = - znfsexport_fs((void *) - (uintptr_t)zc->zc_share.z_exportdata)) - return (error); - break; - case ZFS_SHARE_SMB: - case ZFS_UNSHARE_SMB: - if (error = zsmbexport_fs((void *) - (uintptr_t)zc->zc_share.z_exportdata, - zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? - B_TRUE: B_FALSE)) { - return (error); - } - break; - } - - opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || - zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? - SHAREFS_ADD : SHAREFS_REMOVE; - - /* - * Add or remove share from sharetab - */ - error = zshare_fs(opcode, - (void *)(uintptr_t)zc->zc_share.z_sharedata, - zc->zc_share.z_sharemax); - - return (error); - + return (ENOSYS); } ace_t full_access[] = { @@ -4358,15 +4272,16 @@ zfs_ioc_diff(zfs_cmd_t *zc) /* * Remove all ACL files in shares dir */ +#ifdef HAVE_SHARE static int zfs_smb_acl_purge(znode_t *dzp) { zap_cursor_t zc; zap_attribute_t zap; - zfsvfs_t *zfsvfs = dzp->z_zfsvfs; + zfs_sb_t *zsb = ZTOZSB(dzp); int error; - for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); + for (zap_cursor_init(&zc, zsb->z_os, dzp->z_id); (error = zap_cursor_retrieve(&zc, &zap)) == 0; zap_cursor_advance(&zc)) { if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, @@ -4376,15 +4291,17 @@ zfs_smb_acl_purge(znode_t *dzp) zap_cursor_fini(&zc); return (error); } +#endif /* HAVE SHARE */ static int zfs_ioc_smb_acl(zfs_cmd_t *zc) { +#ifdef HAVE_SHARE vnode_t *vp; znode_t *dzp; vnode_t *resourcevp = NULL; znode_t *sharedir; - zfsvfs_t *zfsvfs; + zfs_sb_t *zsb; nvlist_t *nvlist; char *src, *target; vattr_t vattr; @@ -4405,17 +4322,17 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc) } dzp = VTOZ(vp); - zfsvfs = dzp->z_zfsvfs; - ZFS_ENTER(zfsvfs); + zsb = ZTOZSB(dzp); + ZFS_ENTER(zsb); /* * Create share dir if its missing. */ - mutex_enter(&zfsvfs->z_lock); - if (zfsvfs->z_shares_dir == 0) { + mutex_enter(&zsb->z_lock); + if (zsb->z_shares_dir == 0) { dmu_tx_t *tx; - tx = dmu_tx_create(zfsvfs->z_os); + tx = dmu_tx_create(zsb->z_os); dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, ZFS_SHARES_DIR); dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); @@ -4423,29 +4340,28 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc) if (error) { dmu_tx_abort(tx); } else { - error = zfs_create_share_dir(zfsvfs, tx); + error = zfs_create_share_dir(zsb, tx); dmu_tx_commit(tx); } if (error) { - mutex_exit(&zfsvfs->z_lock); + mutex_exit(&zsb->z_lock); VN_RELE(vp); - ZFS_EXIT(zfsvfs); + ZFS_EXIT(zsb); return (error); } } - mutex_exit(&zfsvfs->z_lock); + mutex_exit(&zsb->z_lock); - ASSERT(zfsvfs->z_shares_dir); - if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { + ASSERT(zsb->z_shares_dir); + if ((error = zfs_zget(zsb, zsb->z_shares_dir, &sharedir)) != 0) { VN_RELE(vp); - ZFS_EXIT(zfsvfs); + ZFS_EXIT(zsb); return (error); } switch (zc->zc_cookie) { case ZFS_SMB_ACL_ADD: vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; - vattr.va_type = VREG; vattr.va_mode = S_IFREG|0777; vattr.va_uid = 0; vattr.va_gid = 0; @@ -4470,7 +4386,7 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc) if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { VN_RELE(vp); - ZFS_EXIT(zfsvfs); + ZFS_EXIT(zsb); return (error); } if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || @@ -4478,7 +4394,7 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc) &target)) { VN_RELE(vp); VN_RELE(ZTOV(sharedir)); - ZFS_EXIT(zfsvfs); + ZFS_EXIT(zsb); nvlist_free(nvlist); return (error); } @@ -4499,9 +4415,12 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc) VN_RELE(vp); VN_RELE(ZTOV(sharedir)); - ZFS_EXIT(zfsvfs); + ZFS_EXIT(zsb); return (error); +#else + return (ENOTSUP); +#endif /* HAVE_SHARE */ } /* @@ -4626,6 +4545,68 @@ zfs_ioc_get_holds(zfs_cmd_t *zc) } /* + * inputs: + * zc_guid flags (ZEVENT_NONBLOCK) + * + * outputs: + * zc_nvlist_dst next nvlist event + * zc_cookie dropped events since last get + * zc_cleanup_fd cleanup-on-exit file descriptor + */ +static int +zfs_ioc_events_next(zfs_cmd_t *zc) +{ + zfs_zevent_t *ze; + nvlist_t *event = NULL; + minor_t minor; + uint64_t dropped = 0; + int error; + + error = zfs_zevent_fd_hold(zc->zc_cleanup_fd, &minor, &ze); + if (error != 0) + return (error); + + do { + error = zfs_zevent_next(ze, &event, + &zc->zc_nvlist_dst_size, &dropped); + if (event != NULL) { + zc->zc_cookie = dropped; + error = put_nvlist(zc, event); + nvlist_free(event); + } + + if (zc->zc_guid & ZEVENT_NONBLOCK) + break; + + if ((error == 0) || (error != ENOENT)) + break; + + error = zfs_zevent_wait(ze); + if (error) + break; + } while (1); + + zfs_zevent_fd_rele(zc->zc_cleanup_fd); + + return (error); +} + +/* + * outputs: + * zc_cookie cleared events count + */ +static int +zfs_ioc_events_clear(zfs_cmd_t *zc) +{ + int count; + + zfs_zevent_drain_all(&count); + zc->zc_cookie = count; + + return 0; +} + +/* * pool create, destroy, and export don't log the history as part of * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export * do the logging of those commands. @@ -4677,6 +4658,10 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = { POOL_CHECK_SUSPENDED }, { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, + { zfs_ioc_create_minor, zfs_secpolicy_config, DATASET_NAME, B_FALSE, + POOL_CHECK_NONE }, + { zfs_ioc_remove_minor, zfs_secpolicy_config, DATASET_NAME, B_FALSE, + POOL_CHECK_NONE }, { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, @@ -4746,7 +4731,11 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = { { zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot, DATASET_NAME, B_FALSE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, { zfs_ioc_obj_to_stats, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, - POOL_CHECK_SUSPENDED } + POOL_CHECK_SUSPENDED }, + { zfs_ioc_events_next, zfs_secpolicy_config, NO_NAME, B_FALSE, + POOL_CHECK_NONE }, + { zfs_ioc_events_clear, zfs_secpolicy_config, NO_NAME, B_FALSE, + POOL_CHECK_NONE }, }; int @@ -4772,13 +4761,56 @@ pool_status_check(const char *name, zfs_ioc_namecheck_t type, return (error); } +static void * +zfsdev_get_state_impl(minor_t minor, enum zfsdev_state_type which) +{ + zfsdev_state_t *zs; + + ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + + for (zs = list_head(&zfsdev_state_list); zs != NULL; + zs = list_next(&zfsdev_state_list, zs)) { + if (zs->zs_minor == minor) { + switch (which) { + case ZST_ONEXIT: return (zs->zs_onexit); + case ZST_ZEVENT: return (zs->zs_zevent); + case ZST_ALL: return (zs); + } + } + } + + return NULL; +} + +void * +zfsdev_get_state(minor_t minor, enum zfsdev_state_type which) +{ + void *ptr; + + mutex_enter(&zfsdev_state_lock); + ptr = zfsdev_get_state_impl(minor, which); + mutex_exit(&zfsdev_state_lock); + + return ptr; +} + +minor_t +zfsdev_getminor(struct file *filp) +{ + ASSERT(filp != NULL); + ASSERT(filp->private_data != NULL); + + return (((zfsdev_state_t *)filp->private_data)->zs_minor); +} + /* - * Find a free minor number. + * Find a free minor number. The zfsdev_state_list is expected to + * be short since it is only a list of currently open file handles. */ minor_t zfsdev_minor_alloc(void) { - static minor_t last_minor; + static minor_t last_minor = 0; minor_t m; ASSERT(MUTEX_HELD(&zfsdev_state_lock)); @@ -4786,7 +4818,7 @@ zfsdev_minor_alloc(void) for (m = last_minor + 1; m != last_minor; m++) { if (m > ZFSDEV_MAX_MINOR) m = 1; - if (ddi_get_soft_state(zfsdev_state, m) == NULL) { + if (zfsdev_get_state_impl(m, ZST_ALL) == NULL) { last_minor = m; return (m); } @@ -4796,116 +4828,94 @@ zfsdev_minor_alloc(void) } static int -zfs_ctldev_init(dev_t *devp) +zfsdev_state_init(struct file *filp) { + zfsdev_state_t *zs; minor_t minor; - zfs_soft_state_t *zs; ASSERT(MUTEX_HELD(&zfsdev_state_lock)); - ASSERT(getminor(*devp) == 0); - minor = zfsdev_minor_alloc(); - if (minor == 0) - return (ENXIO); + minor = zfsdev_minor_alloc(); + if (minor == 0) + return (ENXIO); - if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) - return (EAGAIN); + zs = kmem_zalloc( sizeof(zfsdev_state_t), KM_SLEEP); + if (zs == NULL) + return (ENOMEM); + + zs->zs_file = filp; + zs->zs_minor = minor; + filp->private_data = zs; - *devp = makedevice(getemajor(*devp), minor); + zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit); + zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent); - zs = ddi_get_soft_state(zfsdev_state, minor); - zs->zss_type = ZSST_CTLDEV; - zfs_onexit_init((zfs_onexit_t **)&zs->zss_data); + list_insert_tail(&zfsdev_state_list, zs); return (0); } -static void -zfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor) +static int +zfsdev_state_destroy(struct file *filp) { + zfsdev_state_t *zs; + ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(filp->private_data != NULL); - zfs_onexit_destroy(zo); - ddi_soft_state_free(zfsdev_state, minor); -} + zs = filp->private_data; + zfs_onexit_destroy(zs->zs_onexit); + zfs_zevent_destroy(zs->zs_zevent); -void * -zfsdev_get_soft_state(minor_t minor, enum zfs_soft_state_type which) -{ - zfs_soft_state_t *zp; - - zp = ddi_get_soft_state(zfsdev_state, minor); - if (zp == NULL || zp->zss_type != which) - return (NULL); + list_remove(&zfsdev_state_list, zs); + kmem_free(zs, sizeof(zfsdev_state_t)); - return (zp->zss_data); + return 0; } static int -zfsdev_open(dev_t *devp, int flag, int otyp, cred_t *cr) +zfsdev_open(struct inode *ino, struct file *filp) { - int error = 0; - - if (getminor(*devp) != 0) - return (zvol_open(devp, flag, otyp, cr)); + int error; - /* This is the control device. Allocate a new minor if requested. */ - if (flag & FEXCL) { - mutex_enter(&zfsdev_state_lock); - error = zfs_ctldev_init(devp); - mutex_exit(&zfsdev_state_lock); - } + mutex_enter(&zfsdev_state_lock); + error = zfsdev_state_init(filp); + mutex_exit(&zfsdev_state_lock); - return (error); + return (-error); } static int -zfsdev_close(dev_t dev, int flag, int otyp, cred_t *cr) +zfsdev_release(struct inode *ino, struct file *filp) { - zfs_onexit_t *zo; - minor_t minor = getminor(dev); - - if (minor == 0) - return (0); + int error; mutex_enter(&zfsdev_state_lock); - zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); - if (zo == NULL) { - mutex_exit(&zfsdev_state_lock); - return (zvol_close(dev, flag, otyp, cr)); - } - zfs_ctldev_destroy(zo, minor); + error = zfsdev_state_destroy(filp); mutex_exit(&zfsdev_state_lock); - return (0); + return (-error); } -static int -zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) +static long +zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg) { zfs_cmd_t *zc; uint_t vec; - int error, rc; - minor_t minor = getminor(dev); - - if (minor != 0 && - zfsdev_get_soft_state(minor, ZSST_CTLDEV) == NULL) - return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); + int error, rc, flag = 0; vec = cmd - ZFS_IOC; - ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); - if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) - return (EINVAL); + return (-EINVAL); - zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); + zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP | KM_NODEBUG); error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag); if (error != 0) error = EFAULT; if ((error == 0) && !(flag & FKIOCTL)) - error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); + error = zfs_ioc_vec[vec].zvec_secpolicy(zc, CRED()); /* * Ensure that all pool/dataset names are valid before we pass down to @@ -4948,122 +4958,73 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) } kmem_free(zc, sizeof (zfs_cmd_t)); - return (error); + return (-error); } -static int -zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +#ifdef CONFIG_COMPAT +static long +zfsdev_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg) { - if (cmd != DDI_ATTACH) - return (DDI_FAILURE); - - if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, - DDI_PSEUDO, 0) == DDI_FAILURE) - return (DDI_FAILURE); - - zfs_dip = dip; + return zfsdev_ioctl(filp, cmd, arg); +} +#else +#define zfsdev_compat_ioctl NULL +#endif - ddi_report_dev(dip); +static const struct file_operations zfsdev_fops = { + .open = zfsdev_open, + .release = zfsdev_release, + .unlocked_ioctl = zfsdev_ioctl, + .compat_ioctl = zfsdev_compat_ioctl, + .owner = THIS_MODULE, +}; - return (DDI_SUCCESS); -} +static struct miscdevice zfs_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = ZFS_DRIVER, + .fops = &zfsdev_fops, +}; static int -zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +zfs_attach(void) { - if (spa_busy() || zfs_busy() || zvol_busy()) - return (DDI_FAILURE); - - if (cmd != DDI_DETACH) - return (DDI_FAILURE); + int error; - zfs_dip = NULL; + mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL); + list_create(&zfsdev_state_list, sizeof (zfsdev_state_t), + offsetof(zfsdev_state_t, zs_next)); - ddi_prop_remove_all(dip); - ddi_remove_minor_node(dip, NULL); + error = misc_register(&zfs_misc); + if (error) { + printk(KERN_INFO "ZFS: misc_register() failed %d\n", error); + return (error); + } - return (DDI_SUCCESS); + return (0); } -/*ARGSUSED*/ -static int -zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +static void +zfs_detach(void) { - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - *result = zfs_dip; - return (DDI_SUCCESS); + int error; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)0; - return (DDI_SUCCESS); - } + error = misc_deregister(&zfs_misc); + if (error) + printk(KERN_INFO "ZFS: misc_deregister() failed %d\n", error); - return (DDI_FAILURE); + mutex_destroy(&zfsdev_state_lock); + list_destroy(&zfsdev_state_list); } -/* - * OK, so this is a little weird. - * - * /dev/zfs is the control node, i.e. minor 0. - * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. - * - * /dev/zfs has basically nothing to do except serve up ioctls, - * so most of the standard driver entry points are in zvol.c. - */ -static struct cb_ops zfs_cb_ops = { - zfsdev_open, /* open */ - zfsdev_close, /* close */ - zvol_strategy, /* strategy */ - nodev, /* print */ - zvol_dump, /* dump */ - zvol_read, /* read */ - zvol_write, /* write */ - zfsdev_ioctl, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - ddi_prop_op, /* prop_op */ - NULL, /* streamtab */ - D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ - CB_REV, /* version */ - nodev, /* async read */ - nodev, /* async write */ -}; - -static struct dev_ops zfs_dev_ops = { - DEVO_REV, /* version */ - 0, /* refcnt */ - zfs_info, /* info */ - nulldev, /* identify */ - nulldev, /* probe */ - zfs_attach, /* attach */ - zfs_detach, /* detach */ - nodev, /* reset */ - &zfs_cb_ops, /* driver operations */ - NULL, /* no bus operations */ - NULL, /* power */ - ddi_quiesce_not_needed, /* quiesce */ -}; - -static struct modldrv zfs_modldrv = { - &mod_driverops, - "ZFS storage pool", - &zfs_dev_ops -}; - -static struct modlinkage modlinkage = { - MODREV_1, - (void *)&zfs_modlfs, - (void *)&zfs_modldrv, - NULL -}; - - uint_t zfs_fsyncer_key; extern uint_t rrw_tsd_key; +#ifdef DEBUG +#define ZFS_DEBUG_STR " (DEBUG mode)" +#else +#define ZFS_DEBUG_STR "" +#endif + int _init(void) { @@ -5071,56 +5032,56 @@ _init(void) spa_init(FREAD | FWRITE); zfs_init(); - zvol_init(); - if ((error = mod_install(&modlinkage)) != 0) { - zvol_fini(); - zfs_fini(); - spa_fini(); - return (error); - } + if ((error = zvol_init()) != 0) + goto out1; + + if ((error = zfs_attach()) != 0) + goto out2; tsd_create(&zfs_fsyncer_key, NULL); tsd_create(&rrw_tsd_key, NULL); - error = ldi_ident_from_mod(&modlinkage, &zfs_li); - ASSERT(error == 0); - mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); + printk(KERN_NOTICE "ZFS: Loaded module v%s%s, " + "ZFS pool version %s, ZFS filesystem version %s\n", + ZFS_META_VERSION, ZFS_DEBUG_STR, + SPA_VERSION_STRING, ZPL_VERSION_STRING); return (0); + +out2: + (void) zvol_fini(); +out1: + zfs_fini(); + spa_fini(); + printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s%s" + ", rc = %d\n", ZFS_META_VERSION, ZFS_DEBUG_STR, error); + + return (error); } int _fini(void) { - int error; - - if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) - return (EBUSY); - - if ((error = mod_remove(&modlinkage)) != 0) - return (error); - + zfs_detach(); zvol_fini(); zfs_fini(); spa_fini(); - if (zfs_nfsshare_inited) - (void) ddi_modclose(nfs_mod); - if (zfs_smbshare_inited) - (void) ddi_modclose(smbsrv_mod); - if (zfs_nfsshare_inited || zfs_smbshare_inited) - (void) ddi_modclose(sharefs_mod); tsd_destroy(&zfs_fsyncer_key); - ldi_ident_release(zfs_li); - zfs_li = NULL; - mutex_destroy(&zfs_share_lock); + tsd_destroy(&rrw_tsd_key); - return (error); -} + printk(KERN_NOTICE "ZFS: Unloaded module v%s%s\n", + ZFS_META_VERSION, ZFS_DEBUG_STR); -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); + return (0); } + +#ifdef HAVE_SPL +spl_module_init(_init); +spl_module_exit(_fini); + +MODULE_DESCRIPTION("ZFS"); +MODULE_AUTHOR(ZFS_META_AUTHOR); +MODULE_LICENSE(ZFS_META_LICENSE); +#endif /* HAVE_SPL */