1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 225977Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <sys/types.h> 27789Sahrens #include <sys/param.h> 28789Sahrens #include <sys/errno.h> 29789Sahrens #include <sys/uio.h> 30789Sahrens #include <sys/buf.h> 31789Sahrens #include <sys/modctl.h> 32789Sahrens #include <sys/open.h> 33789Sahrens #include <sys/file.h> 34789Sahrens #include <sys/kmem.h> 35789Sahrens #include <sys/conf.h> 36789Sahrens #include <sys/cmn_err.h> 37789Sahrens #include <sys/stat.h> 38789Sahrens #include <sys/zfs_ioctl.h> 395331Samw #include <sys/zfs_znode.h> 40789Sahrens #include <sys/zap.h> 41789Sahrens #include <sys/spa.h> 423912Slling #include <sys/spa_impl.h> 43789Sahrens #include <sys/vdev.h> 443912Slling #include <sys/vdev_impl.h> 45789Sahrens #include <sys/dmu.h> 46789Sahrens #include <sys/dsl_dir.h> 47789Sahrens #include <sys/dsl_dataset.h> 48789Sahrens #include <sys/dsl_prop.h> 494543Smarks #include <sys/dsl_deleg.h> 504543Smarks #include <sys/dmu_objset.h> 51789Sahrens #include <sys/ddi.h> 52789Sahrens #include <sys/sunddi.h> 53789Sahrens #include <sys/sunldi.h> 54789Sahrens #include <sys/policy.h> 55789Sahrens #include <sys/zone.h> 56789Sahrens #include <sys/nvpair.h> 57789Sahrens #include <sys/pathname.h> 58789Sahrens #include <sys/mount.h> 59789Sahrens #include <sys/sdt.h> 60789Sahrens #include <sys/fs/zfs.h> 61789Sahrens #include <sys/zfs_ctldir.h> 625331Samw #include <sys/zfs_dir.h> 632885Sahrens #include <sys/zvol.h> 644543Smarks #include <sharefs/share.h> 655326Sek110237 #include <sys/dmu_objset.h> 66789Sahrens 67789Sahrens #include "zfs_namecheck.h" 682676Seschrock #include "zfs_prop.h" 694543Smarks #include "zfs_deleg.h" 70789Sahrens 71789Sahrens extern struct modlfs zfs_modlfs; 72789Sahrens 73789Sahrens extern void zfs_init(void); 74789Sahrens extern void zfs_fini(void); 75789Sahrens 76789Sahrens ldi_ident_t zfs_li = NULL; 77789Sahrens dev_info_t *zfs_dip; 78789Sahrens 79789Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 804543Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 81789Sahrens 82789Sahrens typedef struct zfs_ioc_vec { 83789Sahrens zfs_ioc_func_t *zvec_func; 84789Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 85789Sahrens enum { 864577Sahrens NO_NAME, 874577Sahrens POOL_NAME, 884577Sahrens DATASET_NAME 894543Smarks } zvec_namecheck; 904543Smarks boolean_t zvec_his_log; 91789Sahrens } zfs_ioc_vec_t; 92789Sahrens 937265Sahrens static void clear_props(char *dataset, nvlist_t *props); 947184Stimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 957184Stimh boolean_t *); 967184Stimh int zfs_set_prop_nvlist(const char *, nvlist_t *); 977184Stimh 98789Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 99789Sahrens void 100789Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 101789Sahrens { 102789Sahrens const char *newfile; 103789Sahrens char buf[256]; 104789Sahrens va_list adx; 105789Sahrens 106789Sahrens /* 107789Sahrens * Get rid of annoying "../common/" prefix to filename. 108789Sahrens */ 109789Sahrens newfile = strrchr(file, '/'); 110789Sahrens if (newfile != NULL) { 111789Sahrens newfile = newfile + 1; /* Get rid of leading / */ 112789Sahrens } else { 113789Sahrens newfile = file; 114789Sahrens } 115789Sahrens 116789Sahrens va_start(adx, fmt); 117789Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 118789Sahrens va_end(adx); 119789Sahrens 120789Sahrens /* 121789Sahrens * To get this data, use the zfs-dprintf probe as so: 122789Sahrens * dtrace -q -n 'zfs-dprintf \ 123789Sahrens * /stringof(arg0) == "dbuf.c"/ \ 124789Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 125789Sahrens * arg0 = file name 126789Sahrens * arg1 = function name 127789Sahrens * arg2 = line number 128789Sahrens * arg3 = message 129789Sahrens */ 130789Sahrens DTRACE_PROBE4(zfs__dprintf, 131789Sahrens char *, newfile, char *, func, int, line, char *, buf); 132789Sahrens } 133789Sahrens 1344543Smarks static void 1354715Sek110237 history_str_free(char *buf) 1364715Sek110237 { 1374715Sek110237 kmem_free(buf, HIS_MAX_RECORD_LEN); 1384715Sek110237 } 1394715Sek110237 1404715Sek110237 static char * 1414715Sek110237 history_str_get(zfs_cmd_t *zc) 1424715Sek110237 { 1434715Sek110237 char *buf; 1444715Sek110237 1454715Sek110237 if (zc->zc_history == NULL) 1464715Sek110237 return (NULL); 1474715Sek110237 1484715Sek110237 buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 1494715Sek110237 if (copyinstr((void *)(uintptr_t)zc->zc_history, 1504715Sek110237 buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 1514715Sek110237 history_str_free(buf); 1524715Sek110237 return (NULL); 1534715Sek110237 } 1544715Sek110237 1554715Sek110237 buf[HIS_MAX_RECORD_LEN -1] = '\0'; 1564715Sek110237 1574715Sek110237 return (buf); 1584715Sek110237 } 1594715Sek110237 1605375Stimh /* 1617042Sgw25295 * Check to see if the named dataset is currently defined as bootable 1627042Sgw25295 */ 1637042Sgw25295 static boolean_t 1647042Sgw25295 zfs_is_bootfs(const char *name) 1657042Sgw25295 { 1667042Sgw25295 spa_t *spa; 1677042Sgw25295 boolean_t ret = B_FALSE; 1687042Sgw25295 1697042Sgw25295 if (spa_open(name, &spa, FTAG) == 0) { 1707042Sgw25295 if (spa->spa_bootfs) { 1717042Sgw25295 objset_t *os; 1727042Sgw25295 1737042Sgw25295 if (dmu_objset_open(name, DMU_OST_ZFS, 1747042Sgw25295 DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 1757042Sgw25295 ret = (dmu_objset_id(os) == spa->spa_bootfs); 1767042Sgw25295 dmu_objset_close(os); 1777042Sgw25295 } 1787042Sgw25295 } 1797042Sgw25295 spa_close(spa, FTAG); 1807042Sgw25295 } 1817042Sgw25295 return (ret); 1827042Sgw25295 } 1837042Sgw25295 1847042Sgw25295 /* 1857184Stimh * zfs_earlier_version 1865375Stimh * 1875375Stimh * Return non-zero if the spa version is less than requested version. 1885375Stimh */ 1895331Samw static int 1907184Stimh zfs_earlier_version(const char *name, int version) 1915331Samw { 1925331Samw spa_t *spa; 1935331Samw 1945331Samw if (spa_open(name, &spa, FTAG) == 0) { 1955331Samw if (spa_version(spa) < version) { 1965331Samw spa_close(spa, FTAG); 1975331Samw return (1); 1985331Samw } 1995331Samw spa_close(spa, FTAG); 2005331Samw } 2015331Samw return (0); 2025331Samw } 2035331Samw 2045977Smarks /* 2056689Smaybee * zpl_earlier_version 2065977Smarks * 2076689Smaybee * Return TRUE if the ZPL version is less than requested version. 2085977Smarks */ 2096689Smaybee static boolean_t 2106689Smaybee zpl_earlier_version(const char *name, int version) 2115977Smarks { 2125977Smarks objset_t *os; 2136689Smaybee boolean_t rc = B_TRUE; 2145977Smarks 2155977Smarks if (dmu_objset_open(name, DMU_OST_ANY, 2166689Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 2176689Smaybee uint64_t zplversion; 2186689Smaybee 2196689Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 2206689Smaybee rc = zplversion < version; 2215977Smarks dmu_objset_close(os); 2225977Smarks } 2235977Smarks return (rc); 2245977Smarks } 2255977Smarks 2264715Sek110237 static void 2274543Smarks zfs_log_history(zfs_cmd_t *zc) 2284543Smarks { 2294543Smarks spa_t *spa; 2304603Sahrens char *buf; 2314543Smarks 2324715Sek110237 if ((buf = history_str_get(zc)) == NULL) 2334577Sahrens return; 2344577Sahrens 2354715Sek110237 if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 2364715Sek110237 if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 2374715Sek110237 (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 2384715Sek110237 spa_close(spa, FTAG); 2394543Smarks } 2404715Sek110237 history_str_free(buf); 2414543Smarks } 2424543Smarks 243789Sahrens /* 244789Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 245789Sahrens * and can be used in the local zone, as there is no associated dataset. 246789Sahrens */ 247789Sahrens /* ARGSUSED */ 248789Sahrens static int 2494543Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 250789Sahrens { 251789Sahrens return (0); 252789Sahrens } 253789Sahrens 254789Sahrens /* 255789Sahrens * Policy for dataset read operations (list children, get statistics). Requires 256789Sahrens * no privileges, but must be visible in the local zone. 257789Sahrens */ 258789Sahrens /* ARGSUSED */ 259789Sahrens static int 2604543Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 261789Sahrens { 262789Sahrens if (INGLOBALZONE(curproc) || 2634543Smarks zone_dataset_visible(zc->zc_name, NULL)) 264789Sahrens return (0); 265789Sahrens 266789Sahrens return (ENOENT); 267789Sahrens } 268789Sahrens 269789Sahrens static int 270789Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 271789Sahrens { 272789Sahrens uint64_t zoned; 273789Sahrens int writable = 1; 274789Sahrens 275789Sahrens /* 276789Sahrens * The dataset must be visible by this zone -- check this first 277789Sahrens * so they don't see EPERM on something they shouldn't know about. 278789Sahrens */ 279789Sahrens if (!INGLOBALZONE(curproc) && 280789Sahrens !zone_dataset_visible(dataset, &writable)) 281789Sahrens return (ENOENT); 282789Sahrens 283789Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 284789Sahrens return (ENOENT); 285789Sahrens 286789Sahrens if (INGLOBALZONE(curproc)) { 287789Sahrens /* 288789Sahrens * If the fs is zoned, only root can access it from the 289789Sahrens * global zone. 290789Sahrens */ 291789Sahrens if (secpolicy_zfs(cr) && zoned) 292789Sahrens return (EPERM); 293789Sahrens } else { 294789Sahrens /* 295789Sahrens * If we are in a local zone, the 'zoned' property must be set. 296789Sahrens */ 297789Sahrens if (!zoned) 298789Sahrens return (EPERM); 299789Sahrens 300789Sahrens /* must be writable by this zone */ 301789Sahrens if (!writable) 302789Sahrens return (EPERM); 303789Sahrens } 304789Sahrens return (0); 305789Sahrens } 306789Sahrens 307789Sahrens int 3084543Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 309789Sahrens { 310789Sahrens int error; 311789Sahrens 3124543Smarks error = zfs_dozonecheck(name, cr); 3134543Smarks if (error == 0) { 3144543Smarks error = secpolicy_zfs(cr); 3154670Sahrens if (error) 3164543Smarks error = dsl_deleg_access(name, perm, cr); 3174543Smarks } 3184543Smarks return (error); 3194543Smarks } 3204543Smarks 3214543Smarks static int 3224543Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 3234543Smarks { 3244543Smarks /* 3254543Smarks * Check permissions for special properties. 3264543Smarks */ 3274543Smarks switch (prop) { 3284543Smarks case ZFS_PROP_ZONED: 3294543Smarks /* 3304543Smarks * Disallow setting of 'zoned' from within a local zone. 3314543Smarks */ 3324543Smarks if (!INGLOBALZONE(curproc)) 3334543Smarks return (EPERM); 3344543Smarks break; 335789Sahrens 3364543Smarks case ZFS_PROP_QUOTA: 3374543Smarks if (!INGLOBALZONE(curproc)) { 3384543Smarks uint64_t zoned; 3394543Smarks char setpoint[MAXNAMELEN]; 3404543Smarks /* 3414543Smarks * Unprivileged users are allowed to modify the 3424543Smarks * quota on things *under* (ie. contained by) 3434543Smarks * the thing they own. 3444543Smarks */ 3454543Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 3464543Smarks setpoint)) 3474543Smarks return (EPERM); 3484670Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 3494543Smarks return (EPERM); 3504543Smarks } 3514670Sahrens break; 3524543Smarks } 3534543Smarks 3544787Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 355789Sahrens } 356789Sahrens 3574543Smarks int 3584543Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 3594543Smarks { 3604543Smarks int error; 3614543Smarks 3624543Smarks error = zfs_dozonecheck(zc->zc_name, cr); 3634543Smarks if (error) 3644543Smarks return (error); 3654543Smarks 3664543Smarks /* 3674543Smarks * permission to set permissions will be evaluated later in 3684543Smarks * dsl_deleg_can_allow() 3694543Smarks */ 3704543Smarks return (0); 3714543Smarks } 3724543Smarks 3734543Smarks int 3744543Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 3754543Smarks { 3764543Smarks int error; 3774543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 3784543Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 3794543Smarks if (error == 0) 3804543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 3814543Smarks ZFS_DELEG_PERM_MOUNT, cr); 3824543Smarks return (error); 3834543Smarks } 3844543Smarks 3854543Smarks int 3864543Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 3874543Smarks { 3884543Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 3894543Smarks ZFS_DELEG_PERM_SEND, cr)); 3904543Smarks } 3914543Smarks 3924543Smarks int 3934543Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 3944543Smarks { 3954543Smarks if (!INGLOBALZONE(curproc)) 3964543Smarks return (EPERM); 3974543Smarks 3985367Sahrens if (secpolicy_nfs(cr) == 0) { 3994543Smarks return (0); 4004543Smarks } else { 4014543Smarks vnode_t *vp; 4024543Smarks int error; 4034543Smarks 4044543Smarks if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 4054543Smarks NO_FOLLOW, NULL, &vp)) != 0) 4064543Smarks return (error); 4074543Smarks 4084543Smarks /* Now make sure mntpnt and dataset are ZFS */ 4094543Smarks 4104543Smarks if (vp->v_vfsp->vfs_fstype != zfsfstype || 4114543Smarks (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 4124543Smarks zc->zc_name) != 0)) { 4134543Smarks VN_RELE(vp); 4144543Smarks return (EPERM); 4154543Smarks } 4164543Smarks 4174543Smarks VN_RELE(vp); 4184543Smarks return (dsl_deleg_access(zc->zc_name, 4194543Smarks ZFS_DELEG_PERM_SHARE, cr)); 4204543Smarks } 4214543Smarks } 4224543Smarks 423789Sahrens static int 4244543Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 425789Sahrens { 426789Sahrens char *cp; 427789Sahrens 428789Sahrens /* 429789Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 430789Sahrens */ 4314543Smarks (void) strncpy(parent, datasetname, parentsize); 4324543Smarks cp = strrchr(parent, '@'); 433789Sahrens if (cp != NULL) { 434789Sahrens cp[0] = '\0'; 435789Sahrens } else { 4364543Smarks cp = strrchr(parent, '/'); 437789Sahrens if (cp == NULL) 438789Sahrens return (ENOENT); 439789Sahrens cp[0] = '\0'; 440789Sahrens } 441789Sahrens 4424543Smarks return (0); 4434543Smarks } 4444543Smarks 4454543Smarks int 4464543Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 4474543Smarks { 4484543Smarks int error; 4494543Smarks 4504543Smarks if ((error = zfs_secpolicy_write_perms(name, 4514543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 4524543Smarks return (error); 4534543Smarks 4544543Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 4554543Smarks } 4564543Smarks 4574543Smarks static int 4584543Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 4594543Smarks { 4604543Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 4614543Smarks } 4624543Smarks 4634543Smarks /* 4644543Smarks * Must have sys_config privilege to check the iscsi permission 4654543Smarks */ 4664543Smarks /* ARGSUSED */ 4674543Smarks static int 4684543Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 4694543Smarks { 4704543Smarks return (secpolicy_zfs(cr)); 4714543Smarks } 4724543Smarks 4734543Smarks int 4744543Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 4754543Smarks { 4764543Smarks char parentname[MAXNAMELEN]; 4774543Smarks int error; 4784543Smarks 4794543Smarks if ((error = zfs_secpolicy_write_perms(from, 4804543Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 4814543Smarks return (error); 4824543Smarks 4834543Smarks if ((error = zfs_secpolicy_write_perms(from, 4844543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 4854543Smarks return (error); 4864543Smarks 4874543Smarks if ((error = zfs_get_parent(to, parentname, 4884543Smarks sizeof (parentname))) != 0) 4894543Smarks return (error); 4904543Smarks 4914543Smarks if ((error = zfs_secpolicy_write_perms(parentname, 4924543Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 4934543Smarks return (error); 4944543Smarks 4954543Smarks if ((error = zfs_secpolicy_write_perms(parentname, 4964543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 4974543Smarks return (error); 4984543Smarks 4994543Smarks return (error); 5004543Smarks } 5014543Smarks 5024543Smarks static int 5034543Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 5044543Smarks { 5054543Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 5064543Smarks } 5074543Smarks 5084543Smarks static int 5094543Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 5104543Smarks { 5114543Smarks char parentname[MAXNAMELEN]; 5124543Smarks objset_t *clone; 5134543Smarks int error; 5144543Smarks 5154543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 5164543Smarks ZFS_DELEG_PERM_PROMOTE, cr); 5174543Smarks if (error) 5184543Smarks return (error); 5194543Smarks 5204543Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 5216689Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 5224543Smarks 5234543Smarks if (error == 0) { 5244543Smarks dsl_dataset_t *pclone = NULL; 5254543Smarks dsl_dir_t *dd; 5264543Smarks dd = clone->os->os_dsl_dataset->ds_dir; 5274543Smarks 5284543Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 5296689Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 5306689Smaybee dd->dd_phys->dd_origin_obj, FTAG, &pclone); 5314543Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 5324543Smarks if (error) { 5334543Smarks dmu_objset_close(clone); 5344543Smarks return (error); 5354543Smarks } 5364543Smarks 5374543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 5384543Smarks ZFS_DELEG_PERM_MOUNT, cr); 5394543Smarks 5404543Smarks dsl_dataset_name(pclone, parentname); 5414543Smarks dmu_objset_close(clone); 5426689Smaybee dsl_dataset_rele(pclone, FTAG); 5434543Smarks if (error == 0) 5444543Smarks error = zfs_secpolicy_write_perms(parentname, 5454543Smarks ZFS_DELEG_PERM_PROMOTE, cr); 5464543Smarks } 5474543Smarks return (error); 5484543Smarks } 5494543Smarks 5504543Smarks static int 5514543Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 5524543Smarks { 5534543Smarks int error; 5544543Smarks 5554543Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 5564543Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 5574543Smarks return (error); 5584543Smarks 5594543Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 5604543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 5614543Smarks return (error); 5624543Smarks 5634543Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 5644543Smarks ZFS_DELEG_PERM_CREATE, cr)); 5654543Smarks } 5664543Smarks 5674543Smarks int 5684543Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 5694543Smarks { 5704543Smarks int error; 5714543Smarks 5724543Smarks if ((error = zfs_secpolicy_write_perms(name, 5734543Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 5744543Smarks return (error); 5754543Smarks 5764543Smarks error = zfs_secpolicy_write_perms(name, 5774543Smarks ZFS_DELEG_PERM_MOUNT, cr); 5784543Smarks 5794543Smarks return (error); 5804543Smarks } 5814543Smarks 5824543Smarks static int 5834543Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 5844543Smarks { 5854543Smarks 5864543Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 5874543Smarks } 5884543Smarks 5894543Smarks static int 5904543Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 5914543Smarks { 5924543Smarks char parentname[MAXNAMELEN]; 5934543Smarks int error; 5944543Smarks 5954543Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 5964543Smarks sizeof (parentname))) != 0) 5974543Smarks return (error); 5984543Smarks 5994543Smarks if (zc->zc_value[0] != '\0') { 6004543Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 6014543Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 6024543Smarks return (error); 6034543Smarks } 6044543Smarks 6054543Smarks if ((error = zfs_secpolicy_write_perms(parentname, 6064543Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 6074543Smarks return (error); 6084543Smarks 6094543Smarks error = zfs_secpolicy_write_perms(parentname, 6104543Smarks ZFS_DELEG_PERM_MOUNT, cr); 6114543Smarks 6124543Smarks return (error); 6134543Smarks } 6144543Smarks 6154543Smarks static int 6164543Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 6174543Smarks { 6184543Smarks int error; 6194543Smarks 6204543Smarks error = secpolicy_fs_unmount(cr, NULL); 6214543Smarks if (error) { 6224543Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 6234543Smarks } 6244543Smarks return (error); 625789Sahrens } 626789Sahrens 627789Sahrens /* 628789Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 629789Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 630789Sahrens */ 631789Sahrens /* ARGSUSED */ 632789Sahrens static int 6334543Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 634789Sahrens { 635789Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 636789Sahrens return (EPERM); 637789Sahrens 638789Sahrens return (0); 639789Sahrens } 640789Sahrens 641789Sahrens /* 6424543Smarks * Just like zfs_secpolicy_config, except that we will check for 6434543Smarks * mount permission on the dataset for permission to create/remove 6444543Smarks * the minor nodes. 6454543Smarks */ 6464543Smarks static int 6474543Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 6484543Smarks { 6494543Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 6504543Smarks return (dsl_deleg_access(zc->zc_name, 6514543Smarks ZFS_DELEG_PERM_MOUNT, cr)); 6524543Smarks } 6534543Smarks 6544543Smarks return (0); 6554543Smarks } 6564543Smarks 6574543Smarks /* 6581544Seschrock * Policy for fault injection. Requires all privileges. 6591544Seschrock */ 6601544Seschrock /* ARGSUSED */ 6611544Seschrock static int 6624543Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 6631544Seschrock { 6641544Seschrock return (secpolicy_zinject(cr)); 6651544Seschrock } 6661544Seschrock 6674849Sahrens static int 6684849Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 6694849Sahrens { 6704849Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 6714849Sahrens 6725094Slling if (prop == ZPROP_INVAL) { 6734849Sahrens if (!zfs_prop_user(zc->zc_value)) 6744849Sahrens return (EINVAL); 6754849Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 6764849Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 6774849Sahrens } else { 6784849Sahrens if (!zfs_prop_inheritable(prop)) 6794849Sahrens return (EINVAL); 6804849Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 6814849Sahrens } 6824849Sahrens } 6834849Sahrens 6841544Seschrock /* 685789Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 686789Sahrens */ 687789Sahrens static int 6885094Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 689789Sahrens { 690789Sahrens char *packed; 691789Sahrens int error; 6925094Slling nvlist_t *list = NULL; 693789Sahrens 694789Sahrens /* 6952676Seschrock * Read in and unpack the user-supplied nvlist. 696789Sahrens */ 6975094Slling if (size == 0) 698789Sahrens return (EINVAL); 699789Sahrens 700789Sahrens packed = kmem_alloc(size, KM_SLEEP); 701789Sahrens 7025094Slling if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 703789Sahrens kmem_free(packed, size); 704789Sahrens return (error); 705789Sahrens } 706789Sahrens 7075094Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 708789Sahrens kmem_free(packed, size); 709789Sahrens return (error); 710789Sahrens } 711789Sahrens 712789Sahrens kmem_free(packed, size); 713789Sahrens 7145094Slling *nvp = list; 715789Sahrens return (0); 716789Sahrens } 717789Sahrens 718789Sahrens static int 7192676Seschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 7202676Seschrock { 7212676Seschrock char *packed = NULL; 7222676Seschrock size_t size; 7232676Seschrock int error; 7242676Seschrock 7252676Seschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 7262676Seschrock 7272676Seschrock if (size > zc->zc_nvlist_dst_size) { 7282676Seschrock error = ENOMEM; 7292676Seschrock } else { 7304611Smarks packed = kmem_alloc(size, KM_SLEEP); 7312676Seschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 7322676Seschrock KM_SLEEP) == 0); 7332676Seschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 7342676Seschrock size); 7352676Seschrock kmem_free(packed, size); 7362676Seschrock } 7372676Seschrock 7382676Seschrock zc->zc_nvlist_dst_size = size; 7392676Seschrock return (error); 7402676Seschrock } 7412676Seschrock 7422676Seschrock static int 743789Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 744789Sahrens { 745789Sahrens int error; 7465094Slling nvlist_t *config, *props = NULL; 7477184Stimh nvlist_t *rootprops = NULL; 7487184Stimh nvlist_t *zplprops = NULL; 7494715Sek110237 char *buf; 750789Sahrens 7515094Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 7525094Slling &config)) 7534988Sek110237 return (error); 7544715Sek110237 7555094Slling if (zc->zc_nvlist_src_size != 0 && (error = 7565094Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 7575094Slling nvlist_free(config); 7585094Slling return (error); 7595094Slling } 7605094Slling 7617184Stimh if (props) { 7627184Stimh nvlist_t *nvl = NULL; 7637184Stimh uint64_t version = SPA_VERSION; 7647184Stimh 7657184Stimh (void) nvlist_lookup_uint64(props, 7667184Stimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 7677184Stimh if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 7687184Stimh error = EINVAL; 7697184Stimh goto pool_props_bad; 7707184Stimh } 7717184Stimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 7727184Stimh if (nvl) { 7737184Stimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 7747184Stimh if (error != 0) { 7757184Stimh nvlist_free(config); 7767184Stimh nvlist_free(props); 7777184Stimh return (error); 7787184Stimh } 7797184Stimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 7807184Stimh } 7817184Stimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 7827184Stimh error = zfs_fill_zplprops_root(version, rootprops, 7837184Stimh zplprops, NULL); 7847184Stimh if (error) 7857184Stimh goto pool_props_bad; 7867184Stimh } 7877184Stimh 7884988Sek110237 buf = history_str_get(zc); 789789Sahrens 7907184Stimh error = spa_create(zc->zc_name, config, props, buf, zplprops); 7917184Stimh 7927184Stimh /* 7937184Stimh * Set the remaining root properties 7947184Stimh */ 7957184Stimh if (!error && 7967184Stimh (error = zfs_set_prop_nvlist(zc->zc_name, rootprops)) != 0) 7977184Stimh (void) spa_destroy(zc->zc_name); 798789Sahrens 7994988Sek110237 if (buf != NULL) 8004988Sek110237 history_str_free(buf); 8015094Slling 8027184Stimh pool_props_bad: 8037184Stimh nvlist_free(rootprops); 8047184Stimh nvlist_free(zplprops); 805789Sahrens nvlist_free(config); 8067184Stimh nvlist_free(props); 8075094Slling 808789Sahrens return (error); 809789Sahrens } 810789Sahrens 811789Sahrens static int 812789Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 813789Sahrens { 8144543Smarks int error; 8154543Smarks zfs_log_history(zc); 8164543Smarks error = spa_destroy(zc->zc_name); 8174543Smarks return (error); 818789Sahrens } 819789Sahrens 820789Sahrens static int 821789Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 822789Sahrens { 823789Sahrens int error; 8245094Slling nvlist_t *config, *props = NULL; 825789Sahrens uint64_t guid; 826789Sahrens 8275094Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 8285094Slling &config)) != 0) 829789Sahrens return (error); 830789Sahrens 8315094Slling if (zc->zc_nvlist_src_size != 0 && (error = 8325094Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 8335094Slling nvlist_free(config); 8345094Slling return (error); 8355094Slling } 8365094Slling 837789Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 8381544Seschrock guid != zc->zc_guid) 839789Sahrens error = EINVAL; 8406643Seschrock else if (zc->zc_cookie) 8416643Seschrock error = spa_import_faulted(zc->zc_name, config, 8426643Seschrock props); 843789Sahrens else 8445094Slling error = spa_import(zc->zc_name, config, props); 845789Sahrens 846789Sahrens nvlist_free(config); 847789Sahrens 8485094Slling if (props) 8495094Slling nvlist_free(props); 8505094Slling 851789Sahrens return (error); 852789Sahrens } 853789Sahrens 854789Sahrens static int 855789Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 856789Sahrens { 8574543Smarks int error; 8587214Slling boolean_t force = (boolean_t)zc->zc_cookie; 8597214Slling 8604543Smarks zfs_log_history(zc); 8617214Slling error = spa_export(zc->zc_name, NULL, force); 8624543Smarks return (error); 863789Sahrens } 864789Sahrens 865789Sahrens static int 866789Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 867789Sahrens { 868789Sahrens nvlist_t *configs; 869789Sahrens int error; 870789Sahrens 871789Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 872789Sahrens return (EEXIST); 873789Sahrens 8742676Seschrock error = put_nvlist(zc, configs); 875789Sahrens 876789Sahrens nvlist_free(configs); 877789Sahrens 878789Sahrens return (error); 879789Sahrens } 880789Sahrens 881789Sahrens static int 882789Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 883789Sahrens { 884789Sahrens nvlist_t *config; 885789Sahrens int error; 8861544Seschrock int ret = 0; 887789Sahrens 8882676Seschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 8892676Seschrock sizeof (zc->zc_value)); 890789Sahrens 891789Sahrens if (config != NULL) { 8922676Seschrock ret = put_nvlist(zc, config); 893789Sahrens nvlist_free(config); 8941544Seschrock 8951544Seschrock /* 8961544Seschrock * The config may be present even if 'error' is non-zero. 8971544Seschrock * In this case we return success, and preserve the real errno 8981544Seschrock * in 'zc_cookie'. 8991544Seschrock */ 9001544Seschrock zc->zc_cookie = error; 901789Sahrens } else { 9021544Seschrock ret = error; 903789Sahrens } 904789Sahrens 9051544Seschrock return (ret); 906789Sahrens } 907789Sahrens 908789Sahrens /* 909789Sahrens * Try to import the given pool, returning pool stats as appropriate so that 910789Sahrens * user land knows which devices are available and overall pool health. 911789Sahrens */ 912789Sahrens static int 913789Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 914789Sahrens { 915789Sahrens nvlist_t *tryconfig, *config; 916789Sahrens int error; 917789Sahrens 9185094Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 9195094Slling &tryconfig)) != 0) 920789Sahrens return (error); 921789Sahrens 922789Sahrens config = spa_tryimport(tryconfig); 923789Sahrens 924789Sahrens nvlist_free(tryconfig); 925789Sahrens 926789Sahrens if (config == NULL) 927789Sahrens return (EINVAL); 928789Sahrens 9292676Seschrock error = put_nvlist(zc, config); 930789Sahrens nvlist_free(config); 931789Sahrens 932789Sahrens return (error); 933789Sahrens } 934789Sahrens 935789Sahrens static int 936789Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 937789Sahrens { 938789Sahrens spa_t *spa; 939789Sahrens int error; 940789Sahrens 9412926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 9422926Sek110237 return (error); 9432926Sek110237 9447046Sahrens error = spa_scrub(spa, zc->zc_cookie); 9452926Sek110237 9462926Sek110237 spa_close(spa, FTAG); 9472926Sek110237 948789Sahrens return (error); 949789Sahrens } 950789Sahrens 951789Sahrens static int 952789Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 953789Sahrens { 954789Sahrens spa_t *spa; 955789Sahrens int error; 956789Sahrens 957789Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 958789Sahrens if (error == 0) { 959789Sahrens spa_freeze(spa); 960789Sahrens spa_close(spa, FTAG); 961789Sahrens } 962789Sahrens return (error); 963789Sahrens } 964789Sahrens 965789Sahrens static int 9661760Seschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 9671760Seschrock { 9681760Seschrock spa_t *spa; 9691760Seschrock int error; 9701760Seschrock 9712926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 9722926Sek110237 return (error); 9732926Sek110237 9745118Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 9755118Slling spa_close(spa, FTAG); 9765118Slling return (EINVAL); 9775118Slling } 9785118Slling 9795094Slling spa_upgrade(spa, zc->zc_cookie); 9802926Sek110237 spa_close(spa, FTAG); 9812926Sek110237 9822926Sek110237 return (error); 9832926Sek110237 } 9842926Sek110237 9852926Sek110237 static int 9862926Sek110237 zfs_ioc_pool_get_history(zfs_cmd_t *zc) 9872926Sek110237 { 9882926Sek110237 spa_t *spa; 9892926Sek110237 char *hist_buf; 9902926Sek110237 uint64_t size; 9912926Sek110237 int error; 9922926Sek110237 9932926Sek110237 if ((size = zc->zc_history_len) == 0) 9942926Sek110237 return (EINVAL); 9952926Sek110237 9962926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 9972926Sek110237 return (error); 9982926Sek110237 9994577Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 10003863Sek110237 spa_close(spa, FTAG); 10013863Sek110237 return (ENOTSUP); 10023863Sek110237 } 10033863Sek110237 10042926Sek110237 hist_buf = kmem_alloc(size, KM_SLEEP); 10052926Sek110237 if ((error = spa_history_get(spa, &zc->zc_history_offset, 10062926Sek110237 &zc->zc_history_len, hist_buf)) == 0) { 10074543Smarks error = xcopyout(hist_buf, 10084543Smarks (char *)(uintptr_t)zc->zc_history, 10092926Sek110237 zc->zc_history_len); 10102926Sek110237 } 10112926Sek110237 10122926Sek110237 spa_close(spa, FTAG); 10132926Sek110237 kmem_free(hist_buf, size); 10142926Sek110237 return (error); 10152926Sek110237 } 10162926Sek110237 10172926Sek110237 static int 10183444Sek110237 zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 10193444Sek110237 { 10203444Sek110237 int error; 10213444Sek110237 10223912Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 10233444Sek110237 return (error); 10243444Sek110237 10253444Sek110237 return (0); 10263444Sek110237 } 10273444Sek110237 10283444Sek110237 static int 10293444Sek110237 zfs_ioc_obj_to_path(zfs_cmd_t *zc) 10303444Sek110237 { 10313444Sek110237 objset_t *osp; 10323444Sek110237 int error; 10333444Sek110237 10343444Sek110237 if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 10356689Smaybee DS_MODE_USER | DS_MODE_READONLY, &osp)) != 0) 10363444Sek110237 return (error); 10373444Sek110237 error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 10383444Sek110237 sizeof (zc->zc_value)); 10393444Sek110237 dmu_objset_close(osp); 10403444Sek110237 10413444Sek110237 return (error); 10423444Sek110237 } 10433444Sek110237 10443444Sek110237 static int 1045789Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1046789Sahrens { 1047789Sahrens spa_t *spa; 1048789Sahrens int error; 10496423Sgw25295 nvlist_t *config, **l2cache, **spares; 10506423Sgw25295 uint_t nl2cache = 0, nspares = 0; 1051789Sahrens 1052789Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1053789Sahrens if (error != 0) 1054789Sahrens return (error); 1055789Sahrens 10565450Sbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 10575450Sbrendan &config); 10585450Sbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 10595450Sbrendan &l2cache, &nl2cache); 10605450Sbrendan 10616423Sgw25295 (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 10626423Sgw25295 &spares, &nspares); 10636423Sgw25295 10643912Slling /* 10653912Slling * A root pool with concatenated devices is not supported. 10666423Sgw25295 * Thus, can not add a device to a root pool. 10676423Sgw25295 * 10686423Sgw25295 * Intent log device can not be added to a rootpool because 10696423Sgw25295 * during mountroot, zil is replayed, a seperated log device 10706423Sgw25295 * can not be accessed during the mountroot time. 10716423Sgw25295 * 10726423Sgw25295 * l2cache and spare devices are ok to be added to a rootpool. 10733912Slling */ 10746423Sgw25295 if (spa->spa_bootfs != 0 && nl2cache == 0 && nspares == 0) { 10753912Slling spa_close(spa, FTAG); 10763912Slling return (EDOM); 10773912Slling } 10783912Slling 10795450Sbrendan if (error == 0) { 1080789Sahrens error = spa_vdev_add(spa, config); 1081789Sahrens nvlist_free(config); 1082789Sahrens } 1083789Sahrens spa_close(spa, FTAG); 1084789Sahrens return (error); 1085789Sahrens } 1086789Sahrens 1087789Sahrens static int 1088789Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1089789Sahrens { 10902082Seschrock spa_t *spa; 10912082Seschrock int error; 10922082Seschrock 10932082Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 10942082Seschrock if (error != 0) 10952082Seschrock return (error); 10962082Seschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 10972082Seschrock spa_close(spa, FTAG); 10982082Seschrock return (error); 1099789Sahrens } 1100789Sahrens 1101789Sahrens static int 11024451Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1103789Sahrens { 1104789Sahrens spa_t *spa; 1105789Sahrens int error; 11064451Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1107789Sahrens 11082926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1109789Sahrens return (error); 11104451Seschrock switch (zc->zc_cookie) { 11114451Seschrock case VDEV_STATE_ONLINE: 11124451Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 11134451Seschrock break; 11144451Seschrock 11154451Seschrock case VDEV_STATE_OFFLINE: 11164451Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 11174451Seschrock break; 1118789Sahrens 11194451Seschrock case VDEV_STATE_FAULTED: 11204451Seschrock error = vdev_fault(spa, zc->zc_guid); 11214451Seschrock break; 1122789Sahrens 11234451Seschrock case VDEV_STATE_DEGRADED: 11244451Seschrock error = vdev_degrade(spa, zc->zc_guid); 11254451Seschrock break; 11264451Seschrock 11274451Seschrock default: 11284451Seschrock error = EINVAL; 11294451Seschrock } 11304451Seschrock zc->zc_cookie = newstate; 1131789Sahrens spa_close(spa, FTAG); 1132789Sahrens return (error); 1133789Sahrens } 1134789Sahrens 1135789Sahrens static int 1136789Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1137789Sahrens { 1138789Sahrens spa_t *spa; 1139789Sahrens int replacing = zc->zc_cookie; 1140789Sahrens nvlist_t *config; 1141789Sahrens int error; 1142789Sahrens 11432926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1144789Sahrens return (error); 1145789Sahrens 11465094Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 11475094Slling &config)) == 0) { 11481544Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1149789Sahrens nvlist_free(config); 1150789Sahrens } 1151789Sahrens 1152789Sahrens spa_close(spa, FTAG); 1153789Sahrens return (error); 1154789Sahrens } 1155789Sahrens 1156789Sahrens static int 1157789Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1158789Sahrens { 1159789Sahrens spa_t *spa; 1160789Sahrens int error; 1161789Sahrens 11622926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1163789Sahrens return (error); 1164789Sahrens 11651544Seschrock error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 1166789Sahrens 1167789Sahrens spa_close(spa, FTAG); 1168789Sahrens return (error); 1169789Sahrens } 1170789Sahrens 1171789Sahrens static int 11721354Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 11731354Seschrock { 11741354Seschrock spa_t *spa; 11752676Seschrock char *path = zc->zc_value; 11761544Seschrock uint64_t guid = zc->zc_guid; 11771354Seschrock int error; 11781354Seschrock 11791354Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 11801354Seschrock if (error != 0) 11811354Seschrock return (error); 11821354Seschrock 11831354Seschrock error = spa_vdev_setpath(spa, guid, path); 11841354Seschrock spa_close(spa, FTAG); 11851354Seschrock return (error); 11861354Seschrock } 11871354Seschrock 11885367Sahrens /* 11895367Sahrens * inputs: 11905367Sahrens * zc_name name of filesystem 11915367Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 11925367Sahrens * 11935367Sahrens * outputs: 11945367Sahrens * zc_objset_stats stats 11955367Sahrens * zc_nvlist_dst property nvlist 11965367Sahrens * zc_nvlist_dst_size size of property nvlist 11975367Sahrens */ 11981354Seschrock static int 1199789Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1200789Sahrens { 1201789Sahrens objset_t *os = NULL; 1202789Sahrens int error; 12031356Seschrock nvlist_t *nv; 1204789Sahrens 12056689Smaybee if (error = dmu_objset_open(zc->zc_name, 12066689Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1207789Sahrens return (error); 1208789Sahrens 12092885Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1210789Sahrens 12112856Snd150628 if (zc->zc_nvlist_dst != 0 && 12126689Smaybee (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 12132885Sahrens dmu_objset_stats(os, nv); 12143087Sahrens /* 12155147Srm160521 * NB: zvol_get_stats() will read the objset contents, 12163087Sahrens * which we aren't supposed to do with a 12176689Smaybee * DS_MODE_USER hold, because it could be 12183087Sahrens * inconsistent. So this is a bit of a workaround... 12193087Sahrens */ 12204577Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 12214577Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 12224577Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 12234577Sahrens } 12242676Seschrock error = put_nvlist(zc, nv); 12251356Seschrock nvlist_free(nv); 12261356Seschrock } 1227789Sahrens 1228789Sahrens dmu_objset_close(os); 1229789Sahrens return (error); 1230789Sahrens } 1231789Sahrens 12325498Stimh static int 12335498Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 12345498Stimh { 12355498Stimh uint64_t value; 12365498Stimh int error; 12375498Stimh 12385498Stimh /* 12395498Stimh * zfs_get_zplprop() will either find a value or give us 12405498Stimh * the default value (if there is one). 12415498Stimh */ 12425498Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 12435498Stimh return (error); 12445498Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 12455498Stimh return (0); 12465498Stimh } 12475498Stimh 12485498Stimh /* 12495498Stimh * inputs: 12505498Stimh * zc_name name of filesystem 12515498Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 12525498Stimh * 12535498Stimh * outputs: 12545498Stimh * zc_nvlist_dst zpl property nvlist 12555498Stimh * zc_nvlist_dst_size size of zpl property nvlist 12565498Stimh */ 12575498Stimh static int 12585498Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 12595498Stimh { 12605498Stimh objset_t *os; 12615498Stimh int err; 12625498Stimh 12636689Smaybee if (err = dmu_objset_open(zc->zc_name, 12646689Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 12655498Stimh return (err); 12665498Stimh 12675498Stimh dmu_objset_fast_stat(os, &zc->zc_objset_stats); 12685498Stimh 12695498Stimh /* 12705498Stimh * NB: nvl_add_zplprop() will read the objset contents, 12716689Smaybee * which we aren't supposed to do with a DS_MODE_USER 12726689Smaybee * hold, because it could be inconsistent. 12735498Stimh */ 12745498Stimh if (zc->zc_nvlist_dst != NULL && 12755498Stimh !zc->zc_objset_stats.dds_inconsistent && 12765498Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 12775498Stimh nvlist_t *nv; 12785498Stimh 12795498Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 12805498Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 12815498Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 12825498Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 12835498Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 12845498Stimh err = put_nvlist(zc, nv); 12855498Stimh nvlist_free(nv); 12865498Stimh } else { 12875498Stimh err = ENOENT; 12885498Stimh } 12895498Stimh dmu_objset_close(os); 12905498Stimh return (err); 12915498Stimh } 12925498Stimh 12935367Sahrens /* 12945367Sahrens * inputs: 12955367Sahrens * zc_name name of filesystem 12965367Sahrens * zc_cookie zap cursor 12975367Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 12985367Sahrens * 12995367Sahrens * outputs: 13005367Sahrens * zc_name name of next filesystem 13015367Sahrens * zc_objset_stats stats 13025367Sahrens * zc_nvlist_dst property nvlist 13035367Sahrens * zc_nvlist_dst_size size of property nvlist 13045367Sahrens */ 1305789Sahrens static int 1306789Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1307789Sahrens { 1308885Sahrens objset_t *os; 1309789Sahrens int error; 1310789Sahrens char *p; 1311789Sahrens 13126689Smaybee if (error = dmu_objset_open(zc->zc_name, 13136689Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) { 1314885Sahrens if (error == ENOENT) 1315885Sahrens error = ESRCH; 1316885Sahrens return (error); 1317789Sahrens } 1318789Sahrens 1319789Sahrens p = strrchr(zc->zc_name, '/'); 1320789Sahrens if (p == NULL || p[1] != '\0') 1321789Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1322789Sahrens p = zc->zc_name + strlen(zc->zc_name); 1323789Sahrens 1324789Sahrens do { 1325885Sahrens error = dmu_dir_list_next(os, 1326885Sahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 1327885Sahrens NULL, &zc->zc_cookie); 1328789Sahrens if (error == ENOENT) 1329789Sahrens error = ESRCH; 1330885Sahrens } while (error == 0 && !INGLOBALZONE(curproc) && 1331789Sahrens !zone_dataset_visible(zc->zc_name, NULL)); 13326689Smaybee dmu_objset_close(os); 1333789Sahrens 1334885Sahrens /* 1335885Sahrens * If it's a hidden dataset (ie. with a '$' in its name), don't 1336885Sahrens * try to get stats for it. Userland will skip over it. 1337885Sahrens */ 1338885Sahrens if (error == 0 && strchr(zc->zc_name, '$') == NULL) 1339885Sahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1340789Sahrens 1341789Sahrens return (error); 1342789Sahrens } 1343789Sahrens 13445367Sahrens /* 13455367Sahrens * inputs: 13465367Sahrens * zc_name name of filesystem 13475367Sahrens * zc_cookie zap cursor 13485367Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13495367Sahrens * 13505367Sahrens * outputs: 13515367Sahrens * zc_name name of next snapshot 13525367Sahrens * zc_objset_stats stats 13535367Sahrens * zc_nvlist_dst property nvlist 13545367Sahrens * zc_nvlist_dst_size size of property nvlist 13555367Sahrens */ 1356789Sahrens static int 1357789Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1358789Sahrens { 1359885Sahrens objset_t *os; 1360789Sahrens int error; 1361789Sahrens 13626689Smaybee error = dmu_objset_open(zc->zc_name, 13636689Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os); 13646689Smaybee if (error) 13656689Smaybee return (error == ENOENT ? ESRCH : error); 1366789Sahrens 13671003Slling /* 13681003Slling * A dataset name of maximum length cannot have any snapshots, 13691003Slling * so exit immediately. 13701003Slling */ 13711003Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 1372885Sahrens dmu_objset_close(os); 13731003Slling return (ESRCH); 1374789Sahrens } 1375789Sahrens 1376885Sahrens error = dmu_snapshot_list_next(os, 1377885Sahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 13785663Sck153898 zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 13796689Smaybee dmu_objset_close(os); 1380885Sahrens if (error == 0) 1381885Sahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 13826689Smaybee else if (error == ENOENT) 13836689Smaybee error = ESRCH; 1384789Sahrens 13855367Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 13866689Smaybee if (error) 13875367Sahrens *strchr(zc->zc_name, '@') = '\0'; 1388789Sahrens return (error); 1389789Sahrens } 1390789Sahrens 13916423Sgw25295 int 13924787Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1393789Sahrens { 13942676Seschrock nvpair_t *elem; 13952676Seschrock int error; 13962676Seschrock uint64_t intval; 13972676Seschrock char *strval; 13982676Seschrock 13994543Smarks /* 14004543Smarks * First validate permission to set all of the properties 14014543Smarks */ 14022676Seschrock elem = NULL; 14032676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 14044670Sahrens const char *propname = nvpair_name(elem); 14054670Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 14062676Seschrock 14075094Slling if (prop == ZPROP_INVAL) { 14082676Seschrock /* 14092676Seschrock * If this is a user-defined property, it must be a 14102676Seschrock * string, and there is no further validation to do. 14112676Seschrock */ 14122676Seschrock if (!zfs_prop_user(propname) || 14132676Seschrock nvpair_type(elem) != DATA_TYPE_STRING) 14142676Seschrock return (EINVAL); 14152676Seschrock 14165331Samw if (error = zfs_secpolicy_write_perms(name, 14175331Samw ZFS_DELEG_PERM_USERPROP, CRED())) 14184670Sahrens return (error); 14194543Smarks continue; 14202676Seschrock } 14212676Seschrock 14224787Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 14234670Sahrens return (error); 14242676Seschrock 14254670Sahrens /* 14264670Sahrens * Check that this value is valid for this pool version 14274670Sahrens */ 14284670Sahrens switch (prop) { 14293886Sahl case ZFS_PROP_COMPRESSION: 14303886Sahl /* 14313886Sahl * If the user specified gzip compression, make sure 14323886Sahl * the SPA supports it. We ignore any errors here since 14333886Sahl * we'll catch them later. 14343886Sahl */ 14353886Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 14367042Sgw25295 nvpair_value_uint64(elem, &intval) == 0) { 14377042Sgw25295 if (intval >= ZIO_COMPRESS_GZIP_1 && 14387042Sgw25295 intval <= ZIO_COMPRESS_GZIP_9 && 14397184Stimh zfs_earlier_version(name, 14405331Samw SPA_VERSION_GZIP_COMPRESSION)) 14415331Samw return (ENOTSUP); 14427042Sgw25295 14437042Sgw25295 /* 14447042Sgw25295 * If this is a bootable dataset then 14457042Sgw25295 * verify that the compression algorithm 14467042Sgw25295 * is supported for booting. We must return 14477042Sgw25295 * something other than ENOTSUP since it 14487042Sgw25295 * implies a downrev pool version. 14497042Sgw25295 */ 14507042Sgw25295 if (zfs_is_bootfs(name) && 14517042Sgw25295 !BOOTFS_COMPRESS_VALID(intval)) 14527042Sgw25295 return (ERANGE); 14533886Sahl } 14543886Sahl break; 14554603Sahrens 14564603Sahrens case ZFS_PROP_COPIES: 14577184Stimh if (zfs_earlier_version(name, 14587184Stimh SPA_VERSION_DITTO_BLOCKS)) 14595331Samw return (ENOTSUP); 14604603Sahrens break; 14615977Smarks 14625977Smarks case ZFS_PROP_SHARESMB: 14636689Smaybee if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 14645977Smarks return (ENOTSUP); 14655977Smarks break; 14664603Sahrens } 14674543Smarks } 14684543Smarks 14694543Smarks elem = NULL; 14704543Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 14714670Sahrens const char *propname = nvpair_name(elem); 14724670Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 14734543Smarks 14745094Slling if (prop == ZPROP_INVAL) { 14754543Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 14764543Smarks error = dsl_prop_set(name, propname, 1, 14774543Smarks strlen(strval) + 1, strval); 14784543Smarks if (error == 0) 14794543Smarks continue; 14804543Smarks else 14814543Smarks return (error); 14824543Smarks } 14832676Seschrock 14842676Seschrock switch (prop) { 14852676Seschrock case ZFS_PROP_QUOTA: 14862676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 14874577Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 14882676Seschrock return (error); 14892676Seschrock break; 14902676Seschrock 14915378Sck153898 case ZFS_PROP_REFQUOTA: 14925378Sck153898 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 14935378Sck153898 (error = dsl_dataset_set_quota(name, intval)) != 0) 14945378Sck153898 return (error); 14955378Sck153898 break; 14965378Sck153898 14972676Seschrock case ZFS_PROP_RESERVATION: 14982676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 14992676Seschrock (error = dsl_dir_set_reservation(name, 15002676Seschrock intval)) != 0) 15012676Seschrock return (error); 15022676Seschrock break; 1503789Sahrens 15045378Sck153898 case ZFS_PROP_REFRESERVATION: 15055378Sck153898 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15065378Sck153898 (error = dsl_dataset_set_reservation(name, 15075378Sck153898 intval)) != 0) 15085378Sck153898 return (error); 15095378Sck153898 break; 15105378Sck153898 15112676Seschrock case ZFS_PROP_VOLSIZE: 15122676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15134787Sahrens (error = zvol_set_volsize(name, 15144787Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 15152676Seschrock return (error); 15162676Seschrock break; 15172676Seschrock 15182676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 15192676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15204577Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 15214577Sahrens return (error); 15224577Sahrens break; 15234577Sahrens 15244577Sahrens case ZFS_PROP_VERSION: 15254577Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15264577Sahrens (error = zfs_set_version(name, intval)) != 0) 15272676Seschrock return (error); 15282676Seschrock break; 15292676Seschrock 15302676Seschrock default: 15312676Seschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 15322676Seschrock if (zfs_prop_get_type(prop) != 15334787Sahrens PROP_TYPE_STRING) 15342676Seschrock return (EINVAL); 15352717Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 15362717Seschrock if ((error = dsl_prop_set(name, 15372676Seschrock nvpair_name(elem), 1, strlen(strval) + 1, 15382717Seschrock strval)) != 0) 15392717Seschrock return (error); 15402676Seschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 15412885Sahrens const char *unused; 15422885Sahrens 15432717Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 15442676Seschrock 15452676Seschrock switch (zfs_prop_get_type(prop)) { 15464787Sahrens case PROP_TYPE_NUMBER: 15472676Seschrock break; 15484787Sahrens case PROP_TYPE_STRING: 15492717Seschrock return (EINVAL); 15504787Sahrens case PROP_TYPE_INDEX: 15512717Seschrock if (zfs_prop_index_to_string(prop, 15522717Seschrock intval, &unused) != 0) 15532717Seschrock return (EINVAL); 15542676Seschrock break; 15552676Seschrock default: 15564577Sahrens cmn_err(CE_PANIC, 15574577Sahrens "unknown property type"); 15582676Seschrock break; 15592676Seschrock } 15602676Seschrock 15612717Seschrock if ((error = dsl_prop_set(name, propname, 15622717Seschrock 8, 1, &intval)) != 0) 15632717Seschrock return (error); 15642676Seschrock } else { 15652676Seschrock return (EINVAL); 15662676Seschrock } 15672676Seschrock break; 15682676Seschrock } 15692676Seschrock } 15702676Seschrock 15712676Seschrock return (0); 1572789Sahrens } 1573789Sahrens 15745367Sahrens /* 15755367Sahrens * inputs: 15765367Sahrens * zc_name name of filesystem 15775367Sahrens * zc_value name of property to inherit 15785367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 15797265Sahrens * zc_cookie clear existing local props? 15805367Sahrens * 15815367Sahrens * outputs: none 15825367Sahrens */ 1583789Sahrens static int 15842676Seschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1585789Sahrens { 15862676Seschrock nvlist_t *nvl; 15872676Seschrock int error; 1588789Sahrens 15895094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 15905094Slling &nvl)) != 0) 15912676Seschrock return (error); 15922676Seschrock 15937265Sahrens if (zc->zc_cookie) { 15947265Sahrens nvlist_t *origprops; 15957265Sahrens objset_t *os; 15967265Sahrens 15977265Sahrens if (dmu_objset_open(zc->zc_name, DMU_OST_ANY, 15987265Sahrens DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 15997265Sahrens if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 16007265Sahrens clear_props(zc->zc_name, origprops); 16017265Sahrens nvlist_free(origprops); 16027265Sahrens } 16037265Sahrens dmu_objset_close(os); 16047265Sahrens } 16057265Sahrens 16067265Sahrens } 16077265Sahrens 16084787Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 16094543Smarks 16102676Seschrock nvlist_free(nvl); 16112676Seschrock return (error); 1612789Sahrens } 1613789Sahrens 16145367Sahrens /* 16155367Sahrens * inputs: 16165367Sahrens * zc_name name of filesystem 16175367Sahrens * zc_value name of property to inherit 16185367Sahrens * 16195367Sahrens * outputs: none 16205367Sahrens */ 1621789Sahrens static int 16224849Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 16234849Sahrens { 16244849Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 16254849Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 16264849Sahrens } 16274849Sahrens 16284849Sahrens static int 16294098Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 16303912Slling { 16315094Slling nvlist_t *props; 16323912Slling spa_t *spa; 16335094Slling int error; 16343912Slling 16355094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 16365094Slling &props))) 16373912Slling return (error); 16383912Slling 16393912Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 16405094Slling nvlist_free(props); 16413912Slling return (error); 16423912Slling } 16433912Slling 16445094Slling error = spa_prop_set(spa, props); 16453912Slling 16465094Slling nvlist_free(props); 16473912Slling spa_close(spa, FTAG); 16483912Slling 16493912Slling return (error); 16503912Slling } 16513912Slling 16523912Slling static int 16534098Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 16543912Slling { 16553912Slling spa_t *spa; 16563912Slling int error; 16573912Slling nvlist_t *nvp = NULL; 16583912Slling 16593912Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 16603912Slling return (error); 16613912Slling 16625094Slling error = spa_prop_get(spa, &nvp); 16633912Slling 16643912Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 16653912Slling error = put_nvlist(zc, nvp); 16663912Slling else 16673912Slling error = EFAULT; 16683912Slling 16693912Slling spa_close(spa, FTAG); 16703912Slling 16713912Slling if (nvp) 16723912Slling nvlist_free(nvp); 16733912Slling return (error); 16743912Slling } 16753912Slling 16763912Slling static int 16774543Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 16784543Smarks { 16794543Smarks nvlist_t *nvp; 16804543Smarks int error; 16814543Smarks uint32_t uid; 16824543Smarks uint32_t gid; 16834543Smarks uint32_t *groups; 16844543Smarks uint_t group_cnt; 16854543Smarks cred_t *usercred; 16864543Smarks 16875094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 16885094Slling &nvp)) != 0) { 16894543Smarks return (error); 16904543Smarks } 16914543Smarks 16924543Smarks if ((error = nvlist_lookup_uint32(nvp, 16934543Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 16944543Smarks nvlist_free(nvp); 16954543Smarks return (EPERM); 16964543Smarks } 16974543Smarks 16984543Smarks if ((error = nvlist_lookup_uint32(nvp, 16994543Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 17004543Smarks nvlist_free(nvp); 17014543Smarks return (EPERM); 17024543Smarks } 17034543Smarks 17044543Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 17054543Smarks &groups, &group_cnt)) != 0) { 17064543Smarks nvlist_free(nvp); 17074543Smarks return (EPERM); 17084543Smarks } 17094543Smarks usercred = cralloc(); 17104543Smarks if ((crsetugid(usercred, uid, gid) != 0) || 17114543Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 17124543Smarks nvlist_free(nvp); 17134543Smarks crfree(usercred); 17144543Smarks return (EPERM); 17154543Smarks } 17164543Smarks nvlist_free(nvp); 17174543Smarks error = dsl_deleg_access(zc->zc_name, 17184787Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 17194543Smarks crfree(usercred); 17204543Smarks return (error); 17214543Smarks } 17224543Smarks 17235367Sahrens /* 17245367Sahrens * inputs: 17255367Sahrens * zc_name name of filesystem 17265367Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 17275367Sahrens * zc_perm_action allow/unallow flag 17285367Sahrens * 17295367Sahrens * outputs: none 17305367Sahrens */ 17314543Smarks static int 17324543Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 17334543Smarks { 17344543Smarks int error; 17354543Smarks nvlist_t *fsaclnv = NULL; 17364543Smarks 17375094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 17385094Slling &fsaclnv)) != 0) 17394543Smarks return (error); 17404543Smarks 17414543Smarks /* 17424543Smarks * Verify nvlist is constructed correctly 17434543Smarks */ 17444543Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 17454543Smarks nvlist_free(fsaclnv); 17464543Smarks return (EINVAL); 17474543Smarks } 17484543Smarks 17494543Smarks /* 17504543Smarks * If we don't have PRIV_SYS_MOUNT, then validate 17514543Smarks * that user is allowed to hand out each permission in 17524543Smarks * the nvlist(s) 17534543Smarks */ 17544543Smarks 17554787Sahrens error = secpolicy_zfs(CRED()); 17564543Smarks if (error) { 17574787Sahrens if (zc->zc_perm_action == B_FALSE) { 17584787Sahrens error = dsl_deleg_can_allow(zc->zc_name, 17594787Sahrens fsaclnv, CRED()); 17604787Sahrens } else { 17614787Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 17624787Sahrens fsaclnv, CRED()); 17634787Sahrens } 17644543Smarks } 17654543Smarks 17664543Smarks if (error == 0) 17674543Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 17684543Smarks 17694543Smarks nvlist_free(fsaclnv); 17704543Smarks return (error); 17714543Smarks } 17724543Smarks 17735367Sahrens /* 17745367Sahrens * inputs: 17755367Sahrens * zc_name name of filesystem 17765367Sahrens * 17775367Sahrens * outputs: 17785367Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 17795367Sahrens */ 17804543Smarks static int 17814543Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 17824543Smarks { 17834543Smarks nvlist_t *nvp; 17844543Smarks int error; 17854543Smarks 17864543Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 17874543Smarks error = put_nvlist(zc, nvp); 17884543Smarks nvlist_free(nvp); 17894543Smarks } 17904543Smarks 17914543Smarks return (error); 17924543Smarks } 17934543Smarks 17945367Sahrens /* 17955367Sahrens * inputs: 17965367Sahrens * zc_name name of volume 17975367Sahrens * 17985367Sahrens * outputs: none 17995367Sahrens */ 18004543Smarks static int 1801789Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1802789Sahrens { 18034787Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1804789Sahrens } 1805789Sahrens 18065367Sahrens /* 18075367Sahrens * inputs: 18085367Sahrens * zc_name name of volume 18095367Sahrens * 18105367Sahrens * outputs: none 18115367Sahrens */ 1812789Sahrens static int 1813789Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1814789Sahrens { 18152676Seschrock return (zvol_remove_minor(zc->zc_name)); 1816789Sahrens } 1817789Sahrens 1818789Sahrens /* 1819789Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1820789Sahrens * or NULL if no suitable entry is found. The caller of this routine 1821789Sahrens * is responsible for releasing the returned vfs pointer. 1822789Sahrens */ 1823789Sahrens static vfs_t * 1824789Sahrens zfs_get_vfs(const char *resource) 1825789Sahrens { 1826789Sahrens struct vfs *vfsp; 1827789Sahrens struct vfs *vfs_found = NULL; 1828789Sahrens 1829789Sahrens vfs_list_read_lock(); 1830789Sahrens vfsp = rootvfs; 1831789Sahrens do { 1832789Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1833789Sahrens VFS_HOLD(vfsp); 1834789Sahrens vfs_found = vfsp; 1835789Sahrens break; 1836789Sahrens } 1837789Sahrens vfsp = vfsp->vfs_next; 1838789Sahrens } while (vfsp != rootvfs); 1839789Sahrens vfs_list_unlock(); 1840789Sahrens return (vfs_found); 1841789Sahrens } 1842789Sahrens 18434543Smarks /* ARGSUSED */ 1844789Sahrens static void 18454543Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1846789Sahrens { 18475331Samw zfs_creat_t *zct = arg; 18485498Stimh 18495498Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 18505331Samw } 18515331Samw 18525498Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 18535498Stimh 18545331Samw /* 18555498Stimh * inputs: 18567184Stimh * createprops list of properties requested by creator 18577184Stimh * default_zplver zpl version to use if unspecified in createprops 18587184Stimh * fuids_ok fuids allowed in this version of the spa? 18597184Stimh * os parent objset pointer (NULL if root fs) 18605331Samw * 18615498Stimh * outputs: 18625498Stimh * zplprops values for the zplprops we attach to the master node object 18637184Stimh * is_ci true if requested file system will be purely case-insensitive 18645331Samw * 18655498Stimh * Determine the settings for utf8only, normalization and 18665498Stimh * casesensitivity. Specific values may have been requested by the 18675498Stimh * creator and/or we can inherit values from the parent dataset. If 18685498Stimh * the file system is of too early a vintage, a creator can not 18695498Stimh * request settings for these properties, even if the requested 18705498Stimh * setting is the default value. We don't actually want to create dsl 18715498Stimh * properties for these, so remove them from the source nvlist after 18725498Stimh * processing. 18735331Samw */ 18745331Samw static int 18757184Stimh zfs_fill_zplprops_impl(objset_t *os, uint64_t default_zplver, 18767184Stimh boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 18777184Stimh boolean_t *is_ci) 18785331Samw { 18797184Stimh uint64_t zplver = default_zplver; 18805498Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 18815498Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 18825498Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 18835498Stimh 18845498Stimh ASSERT(zplprops != NULL); 18855498Stimh 18865375Stimh /* 18875498Stimh * Pull out creator prop choices, if any. 18885375Stimh */ 18895498Stimh if (createprops) { 18905498Stimh (void) nvlist_lookup_uint64(createprops, 18917184Stimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 18927184Stimh (void) nvlist_lookup_uint64(createprops, 18935498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 18945498Stimh (void) nvlist_remove_all(createprops, 18955498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 18965498Stimh (void) nvlist_lookup_uint64(createprops, 18975498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 18985498Stimh (void) nvlist_remove_all(createprops, 18995498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 19005498Stimh (void) nvlist_lookup_uint64(createprops, 19015498Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 19025498Stimh (void) nvlist_remove_all(createprops, 19035498Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 19045331Samw } 19055331Samw 19065375Stimh /* 19077184Stimh * If the zpl version requested is whacky or the file system 19087184Stimh * or pool is version is too "young" to support normalization 19097184Stimh * and the creator tried to set a value for one of the props, 19107184Stimh * error out. 19115498Stimh */ 19127184Stimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 19137184Stimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 19147184Stimh (zplver < ZPL_VERSION_NORMALIZATION && 19155498Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 19167184Stimh sense != ZFS_PROP_UNDEFINED))) 19175498Stimh return (ENOTSUP); 19185498Stimh 19195498Stimh /* 19205498Stimh * Put the version in the zplprops 19215498Stimh */ 19225498Stimh VERIFY(nvlist_add_uint64(zplprops, 19235498Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 19245498Stimh 19255498Stimh if (norm == ZFS_PROP_UNDEFINED) 19265498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 19275498Stimh VERIFY(nvlist_add_uint64(zplprops, 19285498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 19295498Stimh 19305498Stimh /* 19315498Stimh * If we're normalizing, names must always be valid UTF-8 strings. 19325498Stimh */ 19335498Stimh if (norm) 19345498Stimh u8 = 1; 19355498Stimh if (u8 == ZFS_PROP_UNDEFINED) 19365498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 19375498Stimh VERIFY(nvlist_add_uint64(zplprops, 19385498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 19395498Stimh 19405498Stimh if (sense == ZFS_PROP_UNDEFINED) 19415498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 19425498Stimh VERIFY(nvlist_add_uint64(zplprops, 19435498Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 19445498Stimh 19456492Stimh if (is_ci) 19466492Stimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 19476492Stimh 19487184Stimh return (0); 19497184Stimh } 19507184Stimh 19517184Stimh static int 19527184Stimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 19537184Stimh nvlist_t *zplprops, boolean_t *is_ci) 19547184Stimh { 19557184Stimh boolean_t fuids_ok = B_TRUE; 19567184Stimh uint64_t zplver = ZPL_VERSION; 19577184Stimh objset_t *os = NULL; 19587184Stimh char parentname[MAXNAMELEN]; 19597184Stimh char *cp; 19607184Stimh int error; 19617184Stimh 19627184Stimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 19637184Stimh cp = strrchr(parentname, '/'); 19647184Stimh ASSERT(cp != NULL); 19657184Stimh cp[0] = '\0'; 19667184Stimh 19677184Stimh if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 19687184Stimh zplver = ZPL_VERSION_FUID - 1; 19697184Stimh fuids_ok = B_FALSE; 19707184Stimh } 19717184Stimh 19727184Stimh /* 19737184Stimh * Open parent object set so we can inherit zplprop values. 19747184Stimh */ 19757184Stimh if ((error = dmu_objset_open(parentname, DMU_OST_ANY, 19767184Stimh DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) 19777184Stimh return (error); 19787184Stimh 19797184Stimh error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 19807184Stimh zplprops, is_ci); 19815498Stimh dmu_objset_close(os); 19827184Stimh return (error); 19837184Stimh } 19847184Stimh 19857184Stimh static int 19867184Stimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 19877184Stimh nvlist_t *zplprops, boolean_t *is_ci) 19887184Stimh { 19897184Stimh boolean_t fuids_ok = B_TRUE; 19907184Stimh uint64_t zplver = ZPL_VERSION; 19917184Stimh int error; 19927184Stimh 19937184Stimh if (spa_vers < SPA_VERSION_FUID) { 19947184Stimh zplver = ZPL_VERSION_FUID - 1; 19957184Stimh fuids_ok = B_FALSE; 19967184Stimh } 19977184Stimh 19987184Stimh error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 19997184Stimh zplprops, is_ci); 20007184Stimh return (error); 2001789Sahrens } 2002789Sahrens 20035367Sahrens /* 20045367Sahrens * inputs: 20055367Sahrens * zc_objset_type type of objset to create (fs vs zvol) 20065367Sahrens * zc_name name of new objset 20075367Sahrens * zc_value name of snapshot to clone from (may be empty) 20085367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 20095367Sahrens * 20105498Stimh * outputs: none 20115367Sahrens */ 2012789Sahrens static int 2013789Sahrens zfs_ioc_create(zfs_cmd_t *zc) 2014789Sahrens { 2015789Sahrens objset_t *clone; 2016789Sahrens int error = 0; 20175331Samw zfs_creat_t zct; 20184543Smarks nvlist_t *nvprops = NULL; 20194543Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2020789Sahrens dmu_objset_type_t type = zc->zc_objset_type; 2021789Sahrens 2022789Sahrens switch (type) { 2023789Sahrens 2024789Sahrens case DMU_OST_ZFS: 2025789Sahrens cbfunc = zfs_create_cb; 2026789Sahrens break; 2027789Sahrens 2028789Sahrens case DMU_OST_ZVOL: 2029789Sahrens cbfunc = zvol_create_cb; 2030789Sahrens break; 2031789Sahrens 2032789Sahrens default: 20332199Sahrens cbfunc = NULL; 20346423Sgw25295 break; 20352199Sahrens } 20365326Sek110237 if (strchr(zc->zc_name, '@') || 20375326Sek110237 strchr(zc->zc_name, '%')) 2038789Sahrens return (EINVAL); 2039789Sahrens 20402676Seschrock if (zc->zc_nvlist_src != NULL && 20415094Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 20425094Slling &nvprops)) != 0) 20432676Seschrock return (error); 20442676Seschrock 20455498Stimh zct.zct_zplprops = NULL; 20465331Samw zct.zct_props = nvprops; 20475331Samw 20482676Seschrock if (zc->zc_value[0] != '\0') { 2049789Sahrens /* 2050789Sahrens * We're creating a clone of an existing snapshot. 2051789Sahrens */ 20522676Seschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 20532676Seschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 20544543Smarks nvlist_free(nvprops); 2055789Sahrens return (EINVAL); 20562676Seschrock } 2057789Sahrens 20582676Seschrock error = dmu_objset_open(zc->zc_value, type, 20596689Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 20602676Seschrock if (error) { 20614543Smarks nvlist_free(nvprops); 2062789Sahrens return (error); 20632676Seschrock } 20646492Stimh 20656492Stimh error = dmu_objset_create(zc->zc_name, type, clone, 0, 20666492Stimh NULL, NULL); 20675331Samw if (error) { 20685331Samw dmu_objset_close(clone); 20695331Samw nvlist_free(nvprops); 20705331Samw return (error); 20715331Samw } 2072789Sahrens dmu_objset_close(clone); 2073789Sahrens } else { 20746492Stimh boolean_t is_insensitive = B_FALSE; 20756492Stimh 20762676Seschrock if (cbfunc == NULL) { 20774543Smarks nvlist_free(nvprops); 20782199Sahrens return (EINVAL); 20792676Seschrock } 20802676Seschrock 2081789Sahrens if (type == DMU_OST_ZVOL) { 20822676Seschrock uint64_t volsize, volblocksize; 20832676Seschrock 20844543Smarks if (nvprops == NULL || 20854543Smarks nvlist_lookup_uint64(nvprops, 20862676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 20872676Seschrock &volsize) != 0) { 20884543Smarks nvlist_free(nvprops); 20892676Seschrock return (EINVAL); 20902676Seschrock } 20912676Seschrock 20924543Smarks if ((error = nvlist_lookup_uint64(nvprops, 20932676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 20942676Seschrock &volblocksize)) != 0 && error != ENOENT) { 20954543Smarks nvlist_free(nvprops); 20962676Seschrock return (EINVAL); 20972676Seschrock } 20981133Seschrock 20992676Seschrock if (error != 0) 21002676Seschrock volblocksize = zfs_prop_default_numeric( 21012676Seschrock ZFS_PROP_VOLBLOCKSIZE); 21022676Seschrock 21032676Seschrock if ((error = zvol_check_volblocksize( 21042676Seschrock volblocksize)) != 0 || 21052676Seschrock (error = zvol_check_volsize(volsize, 21062676Seschrock volblocksize)) != 0) { 21074543Smarks nvlist_free(nvprops); 2108789Sahrens return (error); 21092676Seschrock } 21104577Sahrens } else if (type == DMU_OST_ZFS) { 21115331Samw int error; 21125331Samw 21135498Stimh /* 21145331Samw * We have to have normalization and 21155331Samw * case-folding flags correct when we do the 21165331Samw * file system creation, so go figure them out 21175498Stimh * now. 21185331Samw */ 21195498Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 21205498Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 21215498Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 21227184Stimh zct.zct_zplprops, &is_insensitive); 21235331Samw if (error != 0) { 21245331Samw nvlist_free(nvprops); 21255498Stimh nvlist_free(zct.zct_zplprops); 21265331Samw return (error); 21274577Sahrens } 21282676Seschrock } 21296492Stimh error = dmu_objset_create(zc->zc_name, type, NULL, 21306492Stimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 21315498Stimh nvlist_free(zct.zct_zplprops); 2132789Sahrens } 21332676Seschrock 21342676Seschrock /* 21352676Seschrock * It would be nice to do this atomically. 21362676Seschrock */ 21372676Seschrock if (error == 0) { 21384787Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 21392676Seschrock (void) dmu_objset_destroy(zc->zc_name); 21402676Seschrock } 21414543Smarks nvlist_free(nvprops); 2142789Sahrens return (error); 2143789Sahrens } 2144789Sahrens 21457265Sahrens struct snap_prop_arg { 21467265Sahrens nvlist_t *nvprops; 21477265Sahrens const char *snapname; 21487265Sahrens }; 21497265Sahrens 21507265Sahrens static int 21517265Sahrens set_snap_props(char *name, void *arg) 21527265Sahrens { 21537265Sahrens struct snap_prop_arg *snpa = arg; 21547265Sahrens int len = strlen(name) + strlen(snpa->snapname) + 2; 21557265Sahrens char *buf = kmem_alloc(len, KM_SLEEP); 21567265Sahrens int err; 21577265Sahrens 21587265Sahrens (void) snprintf(buf, len, "%s@%s", name, snpa->snapname); 21597265Sahrens err = zfs_set_prop_nvlist(buf, snpa->nvprops); 21607265Sahrens if (err) 21617265Sahrens (void) dmu_objset_destroy(buf); 21627265Sahrens kmem_free(buf, len); 21637265Sahrens return (err); 21647265Sahrens } 21657265Sahrens 21665367Sahrens /* 21675367Sahrens * inputs: 21685367Sahrens * zc_name name of filesystem 21695367Sahrens * zc_value short name of snapshot 21705367Sahrens * zc_cookie recursive flag 21715367Sahrens * 21725367Sahrens * outputs: none 21735367Sahrens */ 2174789Sahrens static int 21752199Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 21762199Sahrens { 21777265Sahrens nvlist_t *nvprops = NULL; 21787265Sahrens int error; 21797265Sahrens boolean_t recursive = zc->zc_cookie; 21807265Sahrens 21812676Seschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 21822199Sahrens return (EINVAL); 21837265Sahrens 21847265Sahrens if (zc->zc_nvlist_src != NULL && 21857265Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 21867265Sahrens &nvprops)) != 0) 21877265Sahrens return (error); 21887265Sahrens 21897265Sahrens error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, recursive); 21907265Sahrens 21917265Sahrens /* 21927265Sahrens * It would be nice to do this atomically. 21937265Sahrens */ 21947265Sahrens if (error == 0) { 21957265Sahrens struct snap_prop_arg snpa; 21967265Sahrens snpa.nvprops = nvprops; 21977265Sahrens snpa.snapname = zc->zc_value; 21987265Sahrens if (recursive) { 21997265Sahrens error = dmu_objset_find(zc->zc_name, 22007265Sahrens set_snap_props, &snpa, DS_FIND_CHILDREN); 22017265Sahrens if (error) { 22027265Sahrens (void) dmu_snapshots_destroy(zc->zc_name, 22037265Sahrens zc->zc_value); 22047265Sahrens } 22057265Sahrens } else { 22067265Sahrens error = set_snap_props(zc->zc_name, &snpa); 22077265Sahrens } 22087265Sahrens } 22097265Sahrens nvlist_free(nvprops); 22107265Sahrens return (error); 22112199Sahrens } 22122199Sahrens 22134007Smmusante int 22142199Sahrens zfs_unmount_snap(char *name, void *arg) 2215789Sahrens { 22162417Sahrens vfs_t *vfsp = NULL; 22172199Sahrens 22186689Smaybee if (arg) { 22196689Smaybee char *snapname = arg; 22206689Smaybee int len = strlen(name) + strlen(snapname) + 2; 22216689Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 22226689Smaybee 22236689Smaybee (void) strcpy(buf, name); 22246689Smaybee (void) strcat(buf, "@"); 22256689Smaybee (void) strcat(buf, snapname); 22266689Smaybee vfsp = zfs_get_vfs(buf); 22276689Smaybee kmem_free(buf, len); 22282417Sahrens } else if (strchr(name, '@')) { 22292199Sahrens vfsp = zfs_get_vfs(name); 22302199Sahrens } 22312199Sahrens 22322199Sahrens if (vfsp) { 22332199Sahrens /* 22342199Sahrens * Always force the unmount for snapshots. 22352199Sahrens */ 22362199Sahrens int flag = MS_FORCE; 2237789Sahrens int err; 2238789Sahrens 22392199Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 22402199Sahrens VFS_RELE(vfsp); 22412199Sahrens return (err); 22422199Sahrens } 22432199Sahrens VFS_RELE(vfsp); 22442199Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 22452199Sahrens return (err); 22462199Sahrens } 22472199Sahrens return (0); 22482199Sahrens } 22492199Sahrens 22505367Sahrens /* 22515367Sahrens * inputs: 22525367Sahrens * zc_name name of filesystem 22535367Sahrens * zc_value short name of snapshot 22545367Sahrens * 22555367Sahrens * outputs: none 22565367Sahrens */ 22572199Sahrens static int 22582199Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 22592199Sahrens { 22602199Sahrens int err; 2261789Sahrens 22622676Seschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 22632199Sahrens return (EINVAL); 22642199Sahrens err = dmu_objset_find(zc->zc_name, 22652676Seschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 22662199Sahrens if (err) 22672199Sahrens return (err); 22682676Seschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 22692199Sahrens } 22702199Sahrens 22715367Sahrens /* 22725367Sahrens * inputs: 22735367Sahrens * zc_name name of dataset to destroy 22745367Sahrens * zc_objset_type type of objset 22755367Sahrens * 22765367Sahrens * outputs: none 22775367Sahrens */ 22782199Sahrens static int 22792199Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 22802199Sahrens { 22812199Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 22822199Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 22832199Sahrens if (err) 22842199Sahrens return (err); 2285789Sahrens } 2286789Sahrens 2287789Sahrens return (dmu_objset_destroy(zc->zc_name)); 2288789Sahrens } 2289789Sahrens 22905367Sahrens /* 22915367Sahrens * inputs: 22925446Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 22935367Sahrens * 22945367Sahrens * outputs: none 22955367Sahrens */ 2296789Sahrens static int 2297789Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2298789Sahrens { 22995446Sahrens objset_t *os; 23005446Sahrens int error; 23015446Sahrens zfsvfs_t *zfsvfs = NULL; 23025446Sahrens 23035446Sahrens /* 23045446Sahrens * Get the zfsvfs for the receiving objset. There 23055446Sahrens * won't be one if we're operating on a zvol, if the 23065446Sahrens * objset doesn't exist yet, or is not mounted. 23075446Sahrens */ 23086689Smaybee error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, DS_MODE_USER, &os); 23095446Sahrens if (error) 23105446Sahrens return (error); 23115446Sahrens 23125446Sahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 23135446Sahrens mutex_enter(&os->os->os_user_ptr_lock); 23145446Sahrens zfsvfs = dmu_objset_get_user(os); 23155446Sahrens if (zfsvfs != NULL) 23165446Sahrens VFS_HOLD(zfsvfs->z_vfs); 23175446Sahrens mutex_exit(&os->os->os_user_ptr_lock); 23185446Sahrens } 23195446Sahrens 23205446Sahrens if (zfsvfs != NULL) { 2321*8012SEric.Taylor@Sun.COM char *osname; 23225446Sahrens int mode; 23235446Sahrens 2324*8012SEric.Taylor@Sun.COM osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 23256083Sek110237 error = zfs_suspend_fs(zfsvfs, osname, &mode); 23266083Sek110237 if (error == 0) { 23276083Sek110237 int resume_err; 23286083Sek110237 23296083Sek110237 ASSERT(strcmp(osname, zc->zc_name) == 0); 23306083Sek110237 error = dmu_objset_rollback(os); 23316083Sek110237 resume_err = zfs_resume_fs(zfsvfs, osname, mode); 23326083Sek110237 error = error ? error : resume_err; 23336083Sek110237 } else { 23346083Sek110237 dmu_objset_close(os); 23356083Sek110237 } 2336*8012SEric.Taylor@Sun.COM kmem_free(osname, MAXNAMELEN); 23375446Sahrens VFS_RELE(zfsvfs->z_vfs); 23385446Sahrens } else { 23395446Sahrens error = dmu_objset_rollback(os); 23405446Sahrens } 23416689Smaybee /* Note, the dmu_objset_rollback() releases the objset for us. */ 23425446Sahrens 23435446Sahrens return (error); 2344789Sahrens } 2345789Sahrens 23465367Sahrens /* 23475367Sahrens * inputs: 23485367Sahrens * zc_name old name of dataset 23495367Sahrens * zc_value new name of dataset 23505367Sahrens * zc_cookie recursive flag (only valid for snapshots) 23515367Sahrens * 23525367Sahrens * outputs: none 23535367Sahrens */ 2354789Sahrens static int 2355789Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2356789Sahrens { 23574490Svb160487 boolean_t recursive = zc->zc_cookie & 1; 23584007Smmusante 23592676Seschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 23605326Sek110237 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 23615326Sek110237 strchr(zc->zc_value, '%')) 2362789Sahrens return (EINVAL); 2363789Sahrens 23644007Smmusante /* 23654007Smmusante * Unmount snapshot unless we're doing a recursive rename, 23664007Smmusante * in which case the dataset code figures out which snapshots 23674007Smmusante * to unmount. 23684007Smmusante */ 23694007Smmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2370789Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 23712199Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 23722199Sahrens if (err) 23732199Sahrens return (err); 2374789Sahrens } 23754007Smmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2376789Sahrens } 2377789Sahrens 23786689Smaybee static void 23796689Smaybee clear_props(char *dataset, nvlist_t *props) 23806689Smaybee { 23816689Smaybee zfs_cmd_t *zc; 23826689Smaybee nvpair_t *prop; 23836689Smaybee 23846689Smaybee if (props == NULL) 23856689Smaybee return; 23866689Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 23876689Smaybee (void) strcpy(zc->zc_name, dataset); 23886689Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 23896689Smaybee prop = nvlist_next_nvpair(props, prop)) { 23906689Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 23916689Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 23926689Smaybee (void) zfs_ioc_inherit_prop(zc); 23936689Smaybee } 23946689Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 23956689Smaybee } 23966689Smaybee 23975367Sahrens /* 23985367Sahrens * inputs: 23995367Sahrens * zc_name name of containing filesystem 24005367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 24015367Sahrens * zc_value name of snapshot to create 24025367Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 24035367Sahrens * zc_cookie file descriptor to recv from 24045367Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 24055367Sahrens * zc_guid force flag 24065367Sahrens * 24075367Sahrens * outputs: 24085367Sahrens * zc_cookie number of bytes read 24095367Sahrens */ 2410789Sahrens static int 24115367Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2412789Sahrens { 2413789Sahrens file_t *fp; 24145326Sek110237 objset_t *os; 24155367Sahrens dmu_recv_cookie_t drc; 24165326Sek110237 zfsvfs_t *zfsvfs = NULL; 24175326Sek110237 boolean_t force = (boolean_t)zc->zc_guid; 2418789Sahrens int error, fd; 24195367Sahrens offset_t off; 24205367Sahrens nvlist_t *props = NULL; 24216689Smaybee nvlist_t *origprops = NULL; 24225367Sahrens objset_t *origin = NULL; 24235367Sahrens char *tosnap; 24245367Sahrens char tofs[ZFS_MAXNAMELEN]; 2425789Sahrens 24263265Sahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 24275326Sek110237 strchr(zc->zc_value, '@') == NULL || 24285326Sek110237 strchr(zc->zc_value, '%')) 24293265Sahrens return (EINVAL); 24303265Sahrens 24315367Sahrens (void) strcpy(tofs, zc->zc_value); 24325367Sahrens tosnap = strchr(tofs, '@'); 24335367Sahrens *tosnap = '\0'; 24345367Sahrens tosnap++; 24355367Sahrens 24365367Sahrens if (zc->zc_nvlist_src != NULL && 24375367Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 24385367Sahrens &props)) != 0) 24395367Sahrens return (error); 24405367Sahrens 2441789Sahrens fd = zc->zc_cookie; 2442789Sahrens fp = getf(fd); 24435367Sahrens if (fp == NULL) { 24445367Sahrens nvlist_free(props); 2445789Sahrens return (EBADF); 24465367Sahrens } 24475326Sek110237 24486689Smaybee if (dmu_objset_open(tofs, DMU_OST_ANY, 24496689Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 24506689Smaybee /* 24516689Smaybee * Try to get the zfsvfs for the receiving objset. 24526689Smaybee * There won't be one if we're operating on a zvol, 24536689Smaybee * if the objset doesn't exist yet, or is not mounted. 24546689Smaybee */ 24555446Sahrens mutex_enter(&os->os->os_user_ptr_lock); 24566689Smaybee if (zfsvfs = dmu_objset_get_user(os)) { 24576083Sek110237 if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) { 24586689Smaybee mutex_exit(&os->os->os_user_ptr_lock); 24596083Sek110237 dmu_objset_close(os); 24606689Smaybee zfsvfs = NULL; 24616689Smaybee error = EBUSY; 24626689Smaybee goto out; 24636083Sek110237 } 24646689Smaybee VFS_HOLD(zfsvfs->z_vfs); 24656083Sek110237 } 24666689Smaybee mutex_exit(&os->os->os_user_ptr_lock); 24676689Smaybee 24686689Smaybee /* 24696689Smaybee * If new properties are supplied, they are to completely 24706689Smaybee * replace the existing ones, so stash away the existing ones. 24716689Smaybee */ 24726689Smaybee if (props) 24736689Smaybee (void) dsl_prop_get_all(os, &origprops, TRUE); 24746689Smaybee 24755326Sek110237 dmu_objset_close(os); 24765326Sek110237 } 24775326Sek110237 24785367Sahrens if (zc->zc_string[0]) { 24795367Sahrens error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 24806689Smaybee DS_MODE_USER | DS_MODE_READONLY, &origin); 24816689Smaybee if (error) 24826689Smaybee goto out; 24835367Sahrens } 24845367Sahrens 24855367Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 24865367Sahrens force, origin, zfsvfs != NULL, &drc); 24875367Sahrens if (origin) 24885367Sahrens dmu_objset_close(origin); 24896689Smaybee if (error) 24906689Smaybee goto out; 24915326Sek110237 24925326Sek110237 /* 24936689Smaybee * Reset properties. We do this before we receive the stream 24946689Smaybee * so that the properties are applied to the new data. 24955326Sek110237 */ 24965367Sahrens if (props) { 24976689Smaybee clear_props(tofs, origprops); 24986689Smaybee /* 24996689Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 25006689Smaybee */ 25016689Smaybee (void) zfs_set_prop_nvlist(tofs, props); 25025367Sahrens } 25035367Sahrens 25045367Sahrens off = fp->f_offset; 25055367Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 25065367Sahrens 25076689Smaybee if (error == 0 && zfsvfs) { 2508*8012SEric.Taylor@Sun.COM char *osname; 25096689Smaybee int mode; 25106689Smaybee 25116689Smaybee /* online recv */ 2512*8012SEric.Taylor@Sun.COM osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 25136689Smaybee error = zfs_suspend_fs(zfsvfs, osname, &mode); 25146689Smaybee if (error == 0) { 25156689Smaybee int resume_err; 25166689Smaybee 25176689Smaybee error = dmu_recv_end(&drc); 25186689Smaybee resume_err = zfs_resume_fs(zfsvfs, osname, mode); 25196689Smaybee error = error ? error : resume_err; 25205367Sahrens } else { 25216689Smaybee dmu_recv_abort_cleanup(&drc); 25225367Sahrens } 2523*8012SEric.Taylor@Sun.COM kmem_free(osname, MAXNAMELEN); 25246689Smaybee } else if (error == 0) { 25256689Smaybee error = dmu_recv_end(&drc); 25266083Sek110237 } 25275367Sahrens 25285367Sahrens zc->zc_cookie = off - fp->f_offset; 25295367Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 25305367Sahrens fp->f_offset = off; 25312885Sahrens 25326689Smaybee /* 25336689Smaybee * On error, restore the original props. 25346689Smaybee */ 25356689Smaybee if (error && props) { 25366689Smaybee clear_props(tofs, props); 25376689Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 25386689Smaybee } 25396689Smaybee out: 25406689Smaybee if (zfsvfs) { 25416689Smaybee mutex_exit(&zfsvfs->z_online_recv_lock); 25426689Smaybee VFS_RELE(zfsvfs->z_vfs); 25436689Smaybee } 25446689Smaybee nvlist_free(props); 25456689Smaybee nvlist_free(origprops); 2546789Sahrens releasef(fd); 2547789Sahrens return (error); 2548789Sahrens } 2549789Sahrens 25505367Sahrens /* 25515367Sahrens * inputs: 25525367Sahrens * zc_name name of snapshot to send 25535367Sahrens * zc_value short name of incremental fromsnap (may be empty) 25545367Sahrens * zc_cookie file descriptor to send stream to 25555367Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 25565367Sahrens * 25575367Sahrens * outputs: none 25585367Sahrens */ 2559789Sahrens static int 25605367Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2561789Sahrens { 2562789Sahrens objset_t *fromsnap = NULL; 2563789Sahrens objset_t *tosnap; 2564789Sahrens file_t *fp; 2565789Sahrens int error; 25665367Sahrens offset_t off; 2567789Sahrens 2568789Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 25696689Smaybee DS_MODE_USER | DS_MODE_READONLY, &tosnap); 2570789Sahrens if (error) 2571789Sahrens return (error); 2572789Sahrens 25732676Seschrock if (zc->zc_value[0] != '\0') { 2574*8012SEric.Taylor@Sun.COM char *buf; 25752885Sahrens char *cp; 25762885Sahrens 2577*8012SEric.Taylor@Sun.COM buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2578*8012SEric.Taylor@Sun.COM (void) strncpy(buf, zc->zc_name, MAXPATHLEN); 25792885Sahrens cp = strchr(buf, '@'); 25802885Sahrens if (cp) 25812885Sahrens *(cp+1) = 0; 2582*8012SEric.Taylor@Sun.COM (void) strncat(buf, zc->zc_value, MAXPATHLEN); 25832885Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 25846689Smaybee DS_MODE_USER | DS_MODE_READONLY, &fromsnap); 2585*8012SEric.Taylor@Sun.COM kmem_free(buf, MAXPATHLEN); 2586789Sahrens if (error) { 2587789Sahrens dmu_objset_close(tosnap); 2588789Sahrens return (error); 2589789Sahrens } 2590789Sahrens } 2591789Sahrens 2592789Sahrens fp = getf(zc->zc_cookie); 2593789Sahrens if (fp == NULL) { 2594789Sahrens dmu_objset_close(tosnap); 2595789Sahrens if (fromsnap) 2596789Sahrens dmu_objset_close(fromsnap); 2597789Sahrens return (EBADF); 2598789Sahrens } 2599789Sahrens 26005367Sahrens off = fp->f_offset; 26015367Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 26025367Sahrens 26035367Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 26045367Sahrens fp->f_offset = off; 2605789Sahrens releasef(zc->zc_cookie); 2606789Sahrens if (fromsnap) 2607789Sahrens dmu_objset_close(fromsnap); 2608789Sahrens dmu_objset_close(tosnap); 2609789Sahrens return (error); 2610789Sahrens } 2611789Sahrens 26121544Seschrock static int 26131544Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 26141544Seschrock { 26151544Seschrock int id, error; 26161544Seschrock 26171544Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 26181544Seschrock &zc->zc_inject_record); 26191544Seschrock 26201544Seschrock if (error == 0) 26211544Seschrock zc->zc_guid = (uint64_t)id; 26221544Seschrock 26231544Seschrock return (error); 26241544Seschrock } 26251544Seschrock 26261544Seschrock static int 26271544Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 26281544Seschrock { 26291544Seschrock return (zio_clear_fault((int)zc->zc_guid)); 26301544Seschrock } 26311544Seschrock 26321544Seschrock static int 26331544Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 26341544Seschrock { 26351544Seschrock int id = (int)zc->zc_guid; 26361544Seschrock int error; 26371544Seschrock 26381544Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 26391544Seschrock &zc->zc_inject_record); 26401544Seschrock 26411544Seschrock zc->zc_guid = id; 26421544Seschrock 26431544Seschrock return (error); 26441544Seschrock } 26451544Seschrock 26461544Seschrock static int 26471544Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 26481544Seschrock { 26491544Seschrock spa_t *spa; 26501544Seschrock int error; 26512676Seschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 26521544Seschrock 26531544Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 26541544Seschrock return (error); 26551544Seschrock 26562676Seschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 26571544Seschrock &count); 26581544Seschrock if (error == 0) 26592676Seschrock zc->zc_nvlist_dst_size = count; 26601544Seschrock else 26612676Seschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 26621544Seschrock 26631544Seschrock spa_close(spa, FTAG); 26641544Seschrock 26651544Seschrock return (error); 26661544Seschrock } 26671544Seschrock 26681544Seschrock static int 26691544Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 26701544Seschrock { 26711544Seschrock spa_t *spa; 26721544Seschrock vdev_t *vd; 26731544Seschrock int error; 26741544Seschrock 26757294Sperrin /* 26767294Sperrin * On zpool clear we also fix up missing slogs 26777294Sperrin */ 26787294Sperrin mutex_enter(&spa_namespace_lock); 26797294Sperrin spa = spa_lookup(zc->zc_name); 26807294Sperrin if (spa == NULL) { 26817294Sperrin mutex_exit(&spa_namespace_lock); 26827294Sperrin return (EIO); 26837294Sperrin } 26847294Sperrin if (spa->spa_log_state == SPA_LOG_MISSING) { 26857294Sperrin /* we need to let spa_open/spa_load clear the chains */ 26867294Sperrin spa->spa_log_state = SPA_LOG_CLEAR; 26877294Sperrin } 26887294Sperrin mutex_exit(&spa_namespace_lock); 26897294Sperrin 26901544Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 26911544Seschrock return (error); 26921544Seschrock 26937754SJeff.Bonwick@Sun.COM spa_vdev_state_enter(spa); 26941544Seschrock 26952676Seschrock if (zc->zc_guid == 0) { 26961544Seschrock vd = NULL; 26976643Seschrock } else { 26986643Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 26995450Sbrendan if (vd == NULL) { 27007754SJeff.Bonwick@Sun.COM (void) spa_vdev_state_exit(spa, NULL, ENODEV); 27015450Sbrendan spa_close(spa, FTAG); 27025450Sbrendan return (ENODEV); 27035450Sbrendan } 27041544Seschrock } 27051544Seschrock 27067754SJeff.Bonwick@Sun.COM vdev_clear(spa, vd); 27077754SJeff.Bonwick@Sun.COM 27087754SJeff.Bonwick@Sun.COM (void) spa_vdev_state_exit(spa, NULL, 0); 27097754SJeff.Bonwick@Sun.COM 27107754SJeff.Bonwick@Sun.COM /* 27117754SJeff.Bonwick@Sun.COM * Resume any suspended I/Os. 27127754SJeff.Bonwick@Sun.COM */ 27137754SJeff.Bonwick@Sun.COM zio_resume(spa); 27141544Seschrock 27151544Seschrock spa_close(spa, FTAG); 27161544Seschrock 27171544Seschrock return (0); 27181544Seschrock } 27191544Seschrock 27205367Sahrens /* 27215367Sahrens * inputs: 27225367Sahrens * zc_name name of filesystem 27235367Sahrens * zc_value name of origin snapshot 27245367Sahrens * 27255367Sahrens * outputs: none 27265367Sahrens */ 27271544Seschrock static int 27282082Seschrock zfs_ioc_promote(zfs_cmd_t *zc) 27292082Seschrock { 27302417Sahrens char *cp; 27312417Sahrens 27322417Sahrens /* 27332417Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 27342417Sahrens * it's easier. 27352417Sahrens */ 27362676Seschrock cp = strchr(zc->zc_value, '@'); 27372417Sahrens if (cp) 27382417Sahrens *cp = '\0'; 27392676Seschrock (void) dmu_objset_find(zc->zc_value, 27402417Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 27412082Seschrock return (dsl_dataset_promote(zc->zc_name)); 27422082Seschrock } 27432082Seschrock 27444543Smarks /* 27454543Smarks * We don't want to have a hard dependency 27464543Smarks * against some special symbols in sharefs 27475331Samw * nfs, and smbsrv. Determine them if needed when 27484543Smarks * the first file system is shared. 27495331Samw * Neither sharefs, nfs or smbsrv are unloadable modules. 27504543Smarks */ 27515331Samw int (*znfsexport_fs)(void *arg); 27524543Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 27535331Samw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 27545331Samw 27555331Samw int zfs_nfsshare_inited; 27565331Samw int zfs_smbshare_inited; 27575331Samw 27584543Smarks ddi_modhandle_t nfs_mod; 27594543Smarks ddi_modhandle_t sharefs_mod; 27605331Samw ddi_modhandle_t smbsrv_mod; 27614543Smarks kmutex_t zfs_share_lock; 27624543Smarks 27634543Smarks static int 27645331Samw zfs_init_sharefs() 27655331Samw { 27665331Samw int error; 27675331Samw 27685331Samw ASSERT(MUTEX_HELD(&zfs_share_lock)); 27695331Samw /* Both NFS and SMB shares also require sharetab support. */ 27705331Samw if (sharefs_mod == NULL && ((sharefs_mod = 27715331Samw ddi_modopen("fs/sharefs", 27725331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 27735331Samw return (ENOSYS); 27745331Samw } 27755331Samw if (zshare_fs == NULL && ((zshare_fs = 27765331Samw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 27775331Samw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 27785331Samw return (ENOSYS); 27795331Samw } 27805331Samw return (0); 27815331Samw } 27825331Samw 27835331Samw static int 27844543Smarks zfs_ioc_share(zfs_cmd_t *zc) 27854543Smarks { 27864543Smarks int error; 27874543Smarks int opcode; 27884543Smarks 27895331Samw switch (zc->zc_share.z_sharetype) { 27905331Samw case ZFS_SHARE_NFS: 27915331Samw case ZFS_UNSHARE_NFS: 27925331Samw if (zfs_nfsshare_inited == 0) { 27935331Samw mutex_enter(&zfs_share_lock); 27945331Samw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 27955331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 27965331Samw mutex_exit(&zfs_share_lock); 27975331Samw return (ENOSYS); 27985331Samw } 27995331Samw if (znfsexport_fs == NULL && 28005331Samw ((znfsexport_fs = (int (*)(void *)) 28015331Samw ddi_modsym(nfs_mod, 28025331Samw "nfs_export", &error)) == NULL)) { 28035331Samw mutex_exit(&zfs_share_lock); 28045331Samw return (ENOSYS); 28055331Samw } 28065331Samw error = zfs_init_sharefs(); 28075331Samw if (error) { 28085331Samw mutex_exit(&zfs_share_lock); 28095331Samw return (ENOSYS); 28105331Samw } 28115331Samw zfs_nfsshare_inited = 1; 28124543Smarks mutex_exit(&zfs_share_lock); 28134543Smarks } 28145331Samw break; 28155331Samw case ZFS_SHARE_SMB: 28165331Samw case ZFS_UNSHARE_SMB: 28175331Samw if (zfs_smbshare_inited == 0) { 28185331Samw mutex_enter(&zfs_share_lock); 28195331Samw if (smbsrv_mod == NULL && ((smbsrv_mod = 28205331Samw ddi_modopen("drv/smbsrv", 28215331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 28225331Samw mutex_exit(&zfs_share_lock); 28235331Samw return (ENOSYS); 28245331Samw } 28255331Samw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 28265331Samw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 28276139Sjb150015 "smb_server_share", &error)) == NULL)) { 28285331Samw mutex_exit(&zfs_share_lock); 28295331Samw return (ENOSYS); 28305331Samw } 28315331Samw error = zfs_init_sharefs(); 28325331Samw if (error) { 28335331Samw mutex_exit(&zfs_share_lock); 28345331Samw return (ENOSYS); 28355331Samw } 28365331Samw zfs_smbshare_inited = 1; 28374543Smarks mutex_exit(&zfs_share_lock); 28384543Smarks } 28395331Samw break; 28405331Samw default: 28415331Samw return (EINVAL); 28424543Smarks } 28434543Smarks 28445331Samw switch (zc->zc_share.z_sharetype) { 28455331Samw case ZFS_SHARE_NFS: 28465331Samw case ZFS_UNSHARE_NFS: 28475331Samw if (error = 28485331Samw znfsexport_fs((void *) 28495331Samw (uintptr_t)zc->zc_share.z_exportdata)) 28505331Samw return (error); 28515331Samw break; 28525331Samw case ZFS_SHARE_SMB: 28535331Samw case ZFS_UNSHARE_SMB: 28545331Samw if (error = zsmbexport_fs((void *) 28555331Samw (uintptr_t)zc->zc_share.z_exportdata, 28565331Samw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 28575331Samw B_TRUE : B_FALSE)) { 28585331Samw return (error); 28595331Samw } 28605331Samw break; 28615331Samw } 28625331Samw 28635331Samw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 28645331Samw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 28654543Smarks SHAREFS_ADD : SHAREFS_REMOVE; 28664543Smarks 28675331Samw /* 28685331Samw * Add or remove share from sharetab 28695331Samw */ 28704543Smarks error = zshare_fs(opcode, 28714543Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 28724543Smarks zc->zc_share.z_sharemax); 28734543Smarks 28744543Smarks return (error); 28754543Smarks 28764543Smarks } 28774543Smarks 28784543Smarks /* 28794988Sek110237 * pool create, destroy, and export don't log the history as part of 28804988Sek110237 * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 28814988Sek110237 * do the logging of those commands. 28824543Smarks */ 2883789Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 28844715Sek110237 { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28854577Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28864577Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28874577Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28884577Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 28894577Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 28904577Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 28914577Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28924577Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 28934577Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28944577Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28954577Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28964577Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28974577Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28984577Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28994577Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29004577Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 29014577Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 29025498Stimh { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 29034543Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 29044577Sahrens DATASET_NAME, B_FALSE }, 29054543Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 29064577Sahrens DATASET_NAME, B_FALSE }, 29074577Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 29084577Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 29094577Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 29104577Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 29114577Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 29124577Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 29134577Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 29145367Sahrens { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 29155367Sahrens { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 29164577Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 29174577Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 29184577Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 29194577Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 29204577Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29214577Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 29224577Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 29234577Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 29244577Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 29254577Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 29264577Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29274577Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 29284577Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 29294577Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 29304543Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 29314577Sahrens DATASET_NAME, B_FALSE }, 29324849Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 29334849Sahrens { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 2934789Sahrens }; 2935789Sahrens 2936789Sahrens static int 2937789Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2938789Sahrens { 2939789Sahrens zfs_cmd_t *zc; 2940789Sahrens uint_t vec; 29412199Sahrens int error, rc; 2942789Sahrens 2943789Sahrens if (getminor(dev) != 0) 2944789Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2945789Sahrens 2946789Sahrens vec = cmd - ZFS_IOC; 29474787Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 2948789Sahrens 2949789Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2950789Sahrens return (EINVAL); 2951789Sahrens 2952789Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2953789Sahrens 2954789Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2955789Sahrens 29564787Sahrens if (error == 0) 29574543Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2958789Sahrens 2959789Sahrens /* 2960789Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2961789Sahrens * the lower layers. 2962789Sahrens */ 2963789Sahrens if (error == 0) { 2964789Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2965789Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 29664577Sahrens case POOL_NAME: 2967789Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2968789Sahrens error = EINVAL; 2969789Sahrens break; 2970789Sahrens 29714577Sahrens case DATASET_NAME: 2972789Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2973789Sahrens error = EINVAL; 2974789Sahrens break; 29752856Snd150628 29764577Sahrens case NO_NAME: 29772856Snd150628 break; 2978789Sahrens } 2979789Sahrens } 2980789Sahrens 2981789Sahrens if (error == 0) 2982789Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2983789Sahrens 29842199Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 29854543Smarks if (error == 0) { 29862199Sahrens error = rc; 29874543Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 29884543Smarks zfs_log_history(zc); 29894543Smarks } 2990789Sahrens 2991789Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 2992789Sahrens return (error); 2993789Sahrens } 2994789Sahrens 2995789Sahrens static int 2996789Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2997789Sahrens { 2998789Sahrens if (cmd != DDI_ATTACH) 2999789Sahrens return (DDI_FAILURE); 3000789Sahrens 3001789Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 3002789Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 3003789Sahrens return (DDI_FAILURE); 3004789Sahrens 3005789Sahrens zfs_dip = dip; 3006789Sahrens 3007789Sahrens ddi_report_dev(dip); 3008789Sahrens 3009789Sahrens return (DDI_SUCCESS); 3010789Sahrens } 3011789Sahrens 3012789Sahrens static int 3013789Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3014789Sahrens { 3015789Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 3016789Sahrens return (DDI_FAILURE); 3017789Sahrens 3018789Sahrens if (cmd != DDI_DETACH) 3019789Sahrens return (DDI_FAILURE); 3020789Sahrens 3021789Sahrens zfs_dip = NULL; 3022789Sahrens 3023789Sahrens ddi_prop_remove_all(dip); 3024789Sahrens ddi_remove_minor_node(dip, NULL); 3025789Sahrens 3026789Sahrens return (DDI_SUCCESS); 3027789Sahrens } 3028789Sahrens 3029789Sahrens /*ARGSUSED*/ 3030789Sahrens static int 3031789Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3032789Sahrens { 3033789Sahrens switch (infocmd) { 3034789Sahrens case DDI_INFO_DEVT2DEVINFO: 3035789Sahrens *result = zfs_dip; 3036789Sahrens return (DDI_SUCCESS); 3037789Sahrens 3038789Sahrens case DDI_INFO_DEVT2INSTANCE: 3039849Sbonwick *result = (void *)0; 3040789Sahrens return (DDI_SUCCESS); 3041789Sahrens } 3042789Sahrens 3043789Sahrens return (DDI_FAILURE); 3044789Sahrens } 3045789Sahrens 3046789Sahrens /* 3047789Sahrens * OK, so this is a little weird. 3048789Sahrens * 3049789Sahrens * /dev/zfs is the control node, i.e. minor 0. 3050789Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3051789Sahrens * 3052789Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 3053789Sahrens * so most of the standard driver entry points are in zvol.c. 3054789Sahrens */ 3055789Sahrens static struct cb_ops zfs_cb_ops = { 3056789Sahrens zvol_open, /* open */ 3057789Sahrens zvol_close, /* close */ 3058789Sahrens zvol_strategy, /* strategy */ 3059789Sahrens nodev, /* print */ 30606423Sgw25295 zvol_dump, /* dump */ 3061789Sahrens zvol_read, /* read */ 3062789Sahrens zvol_write, /* write */ 3063789Sahrens zfsdev_ioctl, /* ioctl */ 3064789Sahrens nodev, /* devmap */ 3065789Sahrens nodev, /* mmap */ 3066789Sahrens nodev, /* segmap */ 3067789Sahrens nochpoll, /* poll */ 3068789Sahrens ddi_prop_op, /* prop_op */ 3069789Sahrens NULL, /* streamtab */ 3070789Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 3071789Sahrens CB_REV, /* version */ 30723638Sbillm nodev, /* async read */ 30733638Sbillm nodev, /* async write */ 3074789Sahrens }; 3075789Sahrens 3076789Sahrens static struct dev_ops zfs_dev_ops = { 3077789Sahrens DEVO_REV, /* version */ 3078789Sahrens 0, /* refcnt */ 3079789Sahrens zfs_info, /* info */ 3080789Sahrens nulldev, /* identify */ 3081789Sahrens nulldev, /* probe */ 3082789Sahrens zfs_attach, /* attach */ 3083789Sahrens zfs_detach, /* detach */ 3084789Sahrens nodev, /* reset */ 3085789Sahrens &zfs_cb_ops, /* driver operations */ 30867656SSherry.Moore@Sun.COM NULL, /* no bus operations */ 30877656SSherry.Moore@Sun.COM NULL, /* power */ 30887656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 3089789Sahrens }; 3090789Sahrens 3091789Sahrens static struct modldrv zfs_modldrv = { 30927656SSherry.Moore@Sun.COM &mod_driverops, 30937656SSherry.Moore@Sun.COM "ZFS storage pool", 30947656SSherry.Moore@Sun.COM &zfs_dev_ops 3095789Sahrens }; 3096789Sahrens 3097789Sahrens static struct modlinkage modlinkage = { 3098789Sahrens MODREV_1, 3099789Sahrens (void *)&zfs_modlfs, 3100789Sahrens (void *)&zfs_modldrv, 3101789Sahrens NULL 3102789Sahrens }; 3103789Sahrens 31044720Sfr157268 31054720Sfr157268 uint_t zfs_fsyncer_key; 31065326Sek110237 extern uint_t rrw_tsd_key; 31074720Sfr157268 3108789Sahrens int 3109789Sahrens _init(void) 3110789Sahrens { 3111789Sahrens int error; 3112789Sahrens 3113849Sbonwick spa_init(FREAD | FWRITE); 3114849Sbonwick zfs_init(); 3115849Sbonwick zvol_init(); 3116849Sbonwick 3117849Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 3118849Sbonwick zvol_fini(); 3119849Sbonwick zfs_fini(); 3120849Sbonwick spa_fini(); 3121789Sahrens return (error); 3122849Sbonwick } 3123789Sahrens 31244720Sfr157268 tsd_create(&zfs_fsyncer_key, NULL); 31255326Sek110237 tsd_create(&rrw_tsd_key, NULL); 31264720Sfr157268 3127789Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 3128789Sahrens ASSERT(error == 0); 31294543Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3130789Sahrens 3131789Sahrens return (0); 3132789Sahrens } 3133789Sahrens 3134789Sahrens int 3135789Sahrens _fini(void) 3136789Sahrens { 3137789Sahrens int error; 3138789Sahrens 31391544Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3140789Sahrens return (EBUSY); 3141789Sahrens 3142789Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3143789Sahrens return (error); 3144789Sahrens 3145789Sahrens zvol_fini(); 3146789Sahrens zfs_fini(); 3147789Sahrens spa_fini(); 31485331Samw if (zfs_nfsshare_inited) 31494543Smarks (void) ddi_modclose(nfs_mod); 31505331Samw if (zfs_smbshare_inited) 31515331Samw (void) ddi_modclose(smbsrv_mod); 31525331Samw if (zfs_nfsshare_inited || zfs_smbshare_inited) 31534543Smarks (void) ddi_modclose(sharefs_mod); 3154789Sahrens 31554720Sfr157268 tsd_destroy(&zfs_fsyncer_key); 3156789Sahrens ldi_ident_release(zfs_li); 3157789Sahrens zfs_li = NULL; 31584543Smarks mutex_destroy(&zfs_share_lock); 3159789Sahrens 3160789Sahrens return (error); 3161789Sahrens } 3162789Sahrens 3163789Sahrens int 3164789Sahrens _info(struct modinfo *modinfop) 3165789Sahrens { 3166789Sahrens return (mod_info(&modlinkage, modinfop)); 3167789Sahrens } 3168