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; 1466*8053SMark.Shellenbaum@Sun.COM 1467*8053SMark.Shellenbaum@Sun.COM case ZFS_PROP_ACLINHERIT: 1468*8053SMark.Shellenbaum@Sun.COM if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1469*8053SMark.Shellenbaum@Sun.COM nvpair_value_uint64(elem, &intval) == 0) 1470*8053SMark.Shellenbaum@Sun.COM if (intval == ZFS_ACL_PASSTHROUGH_X && 1471*8053SMark.Shellenbaum@Sun.COM zfs_earlier_version(name, 1472*8053SMark.Shellenbaum@Sun.COM SPA_VERSION_PASSTHROUGH_X)) 1473*8053SMark.Shellenbaum@Sun.COM return (ENOTSUP); 14744603Sahrens } 14754543Smarks } 14764543Smarks 14774543Smarks elem = NULL; 14784543Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 14794670Sahrens const char *propname = nvpair_name(elem); 14804670Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 14814543Smarks 14825094Slling if (prop == ZPROP_INVAL) { 14834543Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 14844543Smarks error = dsl_prop_set(name, propname, 1, 14854543Smarks strlen(strval) + 1, strval); 14864543Smarks if (error == 0) 14874543Smarks continue; 14884543Smarks else 14894543Smarks return (error); 14904543Smarks } 14912676Seschrock 14922676Seschrock switch (prop) { 14932676Seschrock case ZFS_PROP_QUOTA: 14942676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 14954577Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 14962676Seschrock return (error); 14972676Seschrock break; 14982676Seschrock 14995378Sck153898 case ZFS_PROP_REFQUOTA: 15005378Sck153898 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15015378Sck153898 (error = dsl_dataset_set_quota(name, intval)) != 0) 15025378Sck153898 return (error); 15035378Sck153898 break; 15045378Sck153898 15052676Seschrock case ZFS_PROP_RESERVATION: 15062676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15072676Seschrock (error = dsl_dir_set_reservation(name, 15082676Seschrock intval)) != 0) 15092676Seschrock return (error); 15102676Seschrock break; 1511789Sahrens 15125378Sck153898 case ZFS_PROP_REFRESERVATION: 15135378Sck153898 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15145378Sck153898 (error = dsl_dataset_set_reservation(name, 15155378Sck153898 intval)) != 0) 15165378Sck153898 return (error); 15175378Sck153898 break; 15185378Sck153898 15192676Seschrock case ZFS_PROP_VOLSIZE: 15202676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15214787Sahrens (error = zvol_set_volsize(name, 15224787Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 15232676Seschrock return (error); 15242676Seschrock break; 15252676Seschrock 15262676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 15272676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15284577Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 15294577Sahrens return (error); 15304577Sahrens break; 15314577Sahrens 15324577Sahrens case ZFS_PROP_VERSION: 15334577Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 15344577Sahrens (error = zfs_set_version(name, intval)) != 0) 15352676Seschrock return (error); 15362676Seschrock break; 15372676Seschrock 15382676Seschrock default: 15392676Seschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 15402676Seschrock if (zfs_prop_get_type(prop) != 15414787Sahrens PROP_TYPE_STRING) 15422676Seschrock return (EINVAL); 15432717Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 15442717Seschrock if ((error = dsl_prop_set(name, 15452676Seschrock nvpair_name(elem), 1, strlen(strval) + 1, 15462717Seschrock strval)) != 0) 15472717Seschrock return (error); 15482676Seschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 15492885Sahrens const char *unused; 15502885Sahrens 15512717Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 15522676Seschrock 15532676Seschrock switch (zfs_prop_get_type(prop)) { 15544787Sahrens case PROP_TYPE_NUMBER: 15552676Seschrock break; 15564787Sahrens case PROP_TYPE_STRING: 15572717Seschrock return (EINVAL); 15584787Sahrens case PROP_TYPE_INDEX: 15592717Seschrock if (zfs_prop_index_to_string(prop, 15602717Seschrock intval, &unused) != 0) 15612717Seschrock return (EINVAL); 15622676Seschrock break; 15632676Seschrock default: 15644577Sahrens cmn_err(CE_PANIC, 15654577Sahrens "unknown property type"); 15662676Seschrock break; 15672676Seschrock } 15682676Seschrock 15692717Seschrock if ((error = dsl_prop_set(name, propname, 15702717Seschrock 8, 1, &intval)) != 0) 15712717Seschrock return (error); 15722676Seschrock } else { 15732676Seschrock return (EINVAL); 15742676Seschrock } 15752676Seschrock break; 15762676Seschrock } 15772676Seschrock } 15782676Seschrock 15792676Seschrock return (0); 1580789Sahrens } 1581789Sahrens 15825367Sahrens /* 15835367Sahrens * inputs: 15845367Sahrens * zc_name name of filesystem 15855367Sahrens * zc_value name of property to inherit 15865367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 15877265Sahrens * zc_cookie clear existing local props? 15885367Sahrens * 15895367Sahrens * outputs: none 15905367Sahrens */ 1591789Sahrens static int 15922676Seschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1593789Sahrens { 15942676Seschrock nvlist_t *nvl; 15952676Seschrock int error; 1596789Sahrens 15975094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 15985094Slling &nvl)) != 0) 15992676Seschrock return (error); 16002676Seschrock 16017265Sahrens if (zc->zc_cookie) { 16027265Sahrens nvlist_t *origprops; 16037265Sahrens objset_t *os; 16047265Sahrens 16057265Sahrens if (dmu_objset_open(zc->zc_name, DMU_OST_ANY, 16067265Sahrens DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 16077265Sahrens if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 16087265Sahrens clear_props(zc->zc_name, origprops); 16097265Sahrens nvlist_free(origprops); 16107265Sahrens } 16117265Sahrens dmu_objset_close(os); 16127265Sahrens } 16137265Sahrens 16147265Sahrens } 16157265Sahrens 16164787Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 16174543Smarks 16182676Seschrock nvlist_free(nvl); 16192676Seschrock return (error); 1620789Sahrens } 1621789Sahrens 16225367Sahrens /* 16235367Sahrens * inputs: 16245367Sahrens * zc_name name of filesystem 16255367Sahrens * zc_value name of property to inherit 16265367Sahrens * 16275367Sahrens * outputs: none 16285367Sahrens */ 1629789Sahrens static int 16304849Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 16314849Sahrens { 16324849Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 16334849Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 16344849Sahrens } 16354849Sahrens 16364849Sahrens static int 16374098Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 16383912Slling { 16395094Slling nvlist_t *props; 16403912Slling spa_t *spa; 16415094Slling int error; 16423912Slling 16435094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 16445094Slling &props))) 16453912Slling return (error); 16463912Slling 16473912Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 16485094Slling nvlist_free(props); 16493912Slling return (error); 16503912Slling } 16513912Slling 16525094Slling error = spa_prop_set(spa, props); 16533912Slling 16545094Slling nvlist_free(props); 16553912Slling spa_close(spa, FTAG); 16563912Slling 16573912Slling return (error); 16583912Slling } 16593912Slling 16603912Slling static int 16614098Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 16623912Slling { 16633912Slling spa_t *spa; 16643912Slling int error; 16653912Slling nvlist_t *nvp = NULL; 16663912Slling 16673912Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 16683912Slling return (error); 16693912Slling 16705094Slling error = spa_prop_get(spa, &nvp); 16713912Slling 16723912Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 16733912Slling error = put_nvlist(zc, nvp); 16743912Slling else 16753912Slling error = EFAULT; 16763912Slling 16773912Slling spa_close(spa, FTAG); 16783912Slling 16793912Slling if (nvp) 16803912Slling nvlist_free(nvp); 16813912Slling return (error); 16823912Slling } 16833912Slling 16843912Slling static int 16854543Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 16864543Smarks { 16874543Smarks nvlist_t *nvp; 16884543Smarks int error; 16894543Smarks uint32_t uid; 16904543Smarks uint32_t gid; 16914543Smarks uint32_t *groups; 16924543Smarks uint_t group_cnt; 16934543Smarks cred_t *usercred; 16944543Smarks 16955094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 16965094Slling &nvp)) != 0) { 16974543Smarks return (error); 16984543Smarks } 16994543Smarks 17004543Smarks if ((error = nvlist_lookup_uint32(nvp, 17014543Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 17024543Smarks nvlist_free(nvp); 17034543Smarks return (EPERM); 17044543Smarks } 17054543Smarks 17064543Smarks if ((error = nvlist_lookup_uint32(nvp, 17074543Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 17084543Smarks nvlist_free(nvp); 17094543Smarks return (EPERM); 17104543Smarks } 17114543Smarks 17124543Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 17134543Smarks &groups, &group_cnt)) != 0) { 17144543Smarks nvlist_free(nvp); 17154543Smarks return (EPERM); 17164543Smarks } 17174543Smarks usercred = cralloc(); 17184543Smarks if ((crsetugid(usercred, uid, gid) != 0) || 17194543Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 17204543Smarks nvlist_free(nvp); 17214543Smarks crfree(usercred); 17224543Smarks return (EPERM); 17234543Smarks } 17244543Smarks nvlist_free(nvp); 17254543Smarks error = dsl_deleg_access(zc->zc_name, 17264787Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 17274543Smarks crfree(usercred); 17284543Smarks return (error); 17294543Smarks } 17304543Smarks 17315367Sahrens /* 17325367Sahrens * inputs: 17335367Sahrens * zc_name name of filesystem 17345367Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 17355367Sahrens * zc_perm_action allow/unallow flag 17365367Sahrens * 17375367Sahrens * outputs: none 17385367Sahrens */ 17394543Smarks static int 17404543Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 17414543Smarks { 17424543Smarks int error; 17434543Smarks nvlist_t *fsaclnv = NULL; 17444543Smarks 17455094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 17465094Slling &fsaclnv)) != 0) 17474543Smarks return (error); 17484543Smarks 17494543Smarks /* 17504543Smarks * Verify nvlist is constructed correctly 17514543Smarks */ 17524543Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 17534543Smarks nvlist_free(fsaclnv); 17544543Smarks return (EINVAL); 17554543Smarks } 17564543Smarks 17574543Smarks /* 17584543Smarks * If we don't have PRIV_SYS_MOUNT, then validate 17594543Smarks * that user is allowed to hand out each permission in 17604543Smarks * the nvlist(s) 17614543Smarks */ 17624543Smarks 17634787Sahrens error = secpolicy_zfs(CRED()); 17644543Smarks if (error) { 17654787Sahrens if (zc->zc_perm_action == B_FALSE) { 17664787Sahrens error = dsl_deleg_can_allow(zc->zc_name, 17674787Sahrens fsaclnv, CRED()); 17684787Sahrens } else { 17694787Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 17704787Sahrens fsaclnv, CRED()); 17714787Sahrens } 17724543Smarks } 17734543Smarks 17744543Smarks if (error == 0) 17754543Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 17764543Smarks 17774543Smarks nvlist_free(fsaclnv); 17784543Smarks return (error); 17794543Smarks } 17804543Smarks 17815367Sahrens /* 17825367Sahrens * inputs: 17835367Sahrens * zc_name name of filesystem 17845367Sahrens * 17855367Sahrens * outputs: 17865367Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 17875367Sahrens */ 17884543Smarks static int 17894543Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 17904543Smarks { 17914543Smarks nvlist_t *nvp; 17924543Smarks int error; 17934543Smarks 17944543Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 17954543Smarks error = put_nvlist(zc, nvp); 17964543Smarks nvlist_free(nvp); 17974543Smarks } 17984543Smarks 17994543Smarks return (error); 18004543Smarks } 18014543Smarks 18025367Sahrens /* 18035367Sahrens * inputs: 18045367Sahrens * zc_name name of volume 18055367Sahrens * 18065367Sahrens * outputs: none 18075367Sahrens */ 18084543Smarks static int 1809789Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1810789Sahrens { 18114787Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1812789Sahrens } 1813789Sahrens 18145367Sahrens /* 18155367Sahrens * inputs: 18165367Sahrens * zc_name name of volume 18175367Sahrens * 18185367Sahrens * outputs: none 18195367Sahrens */ 1820789Sahrens static int 1821789Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1822789Sahrens { 18232676Seschrock return (zvol_remove_minor(zc->zc_name)); 1824789Sahrens } 1825789Sahrens 1826789Sahrens /* 1827789Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1828789Sahrens * or NULL if no suitable entry is found. The caller of this routine 1829789Sahrens * is responsible for releasing the returned vfs pointer. 1830789Sahrens */ 1831789Sahrens static vfs_t * 1832789Sahrens zfs_get_vfs(const char *resource) 1833789Sahrens { 1834789Sahrens struct vfs *vfsp; 1835789Sahrens struct vfs *vfs_found = NULL; 1836789Sahrens 1837789Sahrens vfs_list_read_lock(); 1838789Sahrens vfsp = rootvfs; 1839789Sahrens do { 1840789Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1841789Sahrens VFS_HOLD(vfsp); 1842789Sahrens vfs_found = vfsp; 1843789Sahrens break; 1844789Sahrens } 1845789Sahrens vfsp = vfsp->vfs_next; 1846789Sahrens } while (vfsp != rootvfs); 1847789Sahrens vfs_list_unlock(); 1848789Sahrens return (vfs_found); 1849789Sahrens } 1850789Sahrens 18514543Smarks /* ARGSUSED */ 1852789Sahrens static void 18534543Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1854789Sahrens { 18555331Samw zfs_creat_t *zct = arg; 18565498Stimh 18575498Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 18585331Samw } 18595331Samw 18605498Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 18615498Stimh 18625331Samw /* 18635498Stimh * inputs: 18647184Stimh * createprops list of properties requested by creator 18657184Stimh * default_zplver zpl version to use if unspecified in createprops 18667184Stimh * fuids_ok fuids allowed in this version of the spa? 18677184Stimh * os parent objset pointer (NULL if root fs) 18685331Samw * 18695498Stimh * outputs: 18705498Stimh * zplprops values for the zplprops we attach to the master node object 18717184Stimh * is_ci true if requested file system will be purely case-insensitive 18725331Samw * 18735498Stimh * Determine the settings for utf8only, normalization and 18745498Stimh * casesensitivity. Specific values may have been requested by the 18755498Stimh * creator and/or we can inherit values from the parent dataset. If 18765498Stimh * the file system is of too early a vintage, a creator can not 18775498Stimh * request settings for these properties, even if the requested 18785498Stimh * setting is the default value. We don't actually want to create dsl 18795498Stimh * properties for these, so remove them from the source nvlist after 18805498Stimh * processing. 18815331Samw */ 18825331Samw static int 18837184Stimh zfs_fill_zplprops_impl(objset_t *os, uint64_t default_zplver, 18847184Stimh boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 18857184Stimh boolean_t *is_ci) 18865331Samw { 18877184Stimh uint64_t zplver = default_zplver; 18885498Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 18895498Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 18905498Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 18915498Stimh 18925498Stimh ASSERT(zplprops != NULL); 18935498Stimh 18945375Stimh /* 18955498Stimh * Pull out creator prop choices, if any. 18965375Stimh */ 18975498Stimh if (createprops) { 18985498Stimh (void) nvlist_lookup_uint64(createprops, 18997184Stimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 19007184Stimh (void) nvlist_lookup_uint64(createprops, 19015498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 19025498Stimh (void) nvlist_remove_all(createprops, 19035498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 19045498Stimh (void) nvlist_lookup_uint64(createprops, 19055498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 19065498Stimh (void) nvlist_remove_all(createprops, 19075498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 19085498Stimh (void) nvlist_lookup_uint64(createprops, 19095498Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 19105498Stimh (void) nvlist_remove_all(createprops, 19115498Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 19125331Samw } 19135331Samw 19145375Stimh /* 19157184Stimh * If the zpl version requested is whacky or the file system 19167184Stimh * or pool is version is too "young" to support normalization 19177184Stimh * and the creator tried to set a value for one of the props, 19187184Stimh * error out. 19195498Stimh */ 19207184Stimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 19217184Stimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 19227184Stimh (zplver < ZPL_VERSION_NORMALIZATION && 19235498Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 19247184Stimh sense != ZFS_PROP_UNDEFINED))) 19255498Stimh return (ENOTSUP); 19265498Stimh 19275498Stimh /* 19285498Stimh * Put the version in the zplprops 19295498Stimh */ 19305498Stimh VERIFY(nvlist_add_uint64(zplprops, 19315498Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 19325498Stimh 19335498Stimh if (norm == ZFS_PROP_UNDEFINED) 19345498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 19355498Stimh VERIFY(nvlist_add_uint64(zplprops, 19365498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 19375498Stimh 19385498Stimh /* 19395498Stimh * If we're normalizing, names must always be valid UTF-8 strings. 19405498Stimh */ 19415498Stimh if (norm) 19425498Stimh u8 = 1; 19435498Stimh if (u8 == ZFS_PROP_UNDEFINED) 19445498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 19455498Stimh VERIFY(nvlist_add_uint64(zplprops, 19465498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 19475498Stimh 19485498Stimh if (sense == ZFS_PROP_UNDEFINED) 19495498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 19505498Stimh VERIFY(nvlist_add_uint64(zplprops, 19515498Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 19525498Stimh 19536492Stimh if (is_ci) 19546492Stimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 19556492Stimh 19567184Stimh return (0); 19577184Stimh } 19587184Stimh 19597184Stimh static int 19607184Stimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 19617184Stimh nvlist_t *zplprops, boolean_t *is_ci) 19627184Stimh { 19637184Stimh boolean_t fuids_ok = B_TRUE; 19647184Stimh uint64_t zplver = ZPL_VERSION; 19657184Stimh objset_t *os = NULL; 19667184Stimh char parentname[MAXNAMELEN]; 19677184Stimh char *cp; 19687184Stimh int error; 19697184Stimh 19707184Stimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 19717184Stimh cp = strrchr(parentname, '/'); 19727184Stimh ASSERT(cp != NULL); 19737184Stimh cp[0] = '\0'; 19747184Stimh 19757184Stimh if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 19767184Stimh zplver = ZPL_VERSION_FUID - 1; 19777184Stimh fuids_ok = B_FALSE; 19787184Stimh } 19797184Stimh 19807184Stimh /* 19817184Stimh * Open parent object set so we can inherit zplprop values. 19827184Stimh */ 19837184Stimh if ((error = dmu_objset_open(parentname, DMU_OST_ANY, 19847184Stimh DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) 19857184Stimh return (error); 19867184Stimh 19877184Stimh error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 19887184Stimh zplprops, is_ci); 19895498Stimh dmu_objset_close(os); 19907184Stimh return (error); 19917184Stimh } 19927184Stimh 19937184Stimh static int 19947184Stimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 19957184Stimh nvlist_t *zplprops, boolean_t *is_ci) 19967184Stimh { 19977184Stimh boolean_t fuids_ok = B_TRUE; 19987184Stimh uint64_t zplver = ZPL_VERSION; 19997184Stimh int error; 20007184Stimh 20017184Stimh if (spa_vers < SPA_VERSION_FUID) { 20027184Stimh zplver = ZPL_VERSION_FUID - 1; 20037184Stimh fuids_ok = B_FALSE; 20047184Stimh } 20057184Stimh 20067184Stimh error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 20077184Stimh zplprops, is_ci); 20087184Stimh return (error); 2009789Sahrens } 2010789Sahrens 20115367Sahrens /* 20125367Sahrens * inputs: 20135367Sahrens * zc_objset_type type of objset to create (fs vs zvol) 20145367Sahrens * zc_name name of new objset 20155367Sahrens * zc_value name of snapshot to clone from (may be empty) 20165367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 20175367Sahrens * 20185498Stimh * outputs: none 20195367Sahrens */ 2020789Sahrens static int 2021789Sahrens zfs_ioc_create(zfs_cmd_t *zc) 2022789Sahrens { 2023789Sahrens objset_t *clone; 2024789Sahrens int error = 0; 20255331Samw zfs_creat_t zct; 20264543Smarks nvlist_t *nvprops = NULL; 20274543Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2028789Sahrens dmu_objset_type_t type = zc->zc_objset_type; 2029789Sahrens 2030789Sahrens switch (type) { 2031789Sahrens 2032789Sahrens case DMU_OST_ZFS: 2033789Sahrens cbfunc = zfs_create_cb; 2034789Sahrens break; 2035789Sahrens 2036789Sahrens case DMU_OST_ZVOL: 2037789Sahrens cbfunc = zvol_create_cb; 2038789Sahrens break; 2039789Sahrens 2040789Sahrens default: 20412199Sahrens cbfunc = NULL; 20426423Sgw25295 break; 20432199Sahrens } 20445326Sek110237 if (strchr(zc->zc_name, '@') || 20455326Sek110237 strchr(zc->zc_name, '%')) 2046789Sahrens return (EINVAL); 2047789Sahrens 20482676Seschrock if (zc->zc_nvlist_src != NULL && 20495094Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 20505094Slling &nvprops)) != 0) 20512676Seschrock return (error); 20522676Seschrock 20535498Stimh zct.zct_zplprops = NULL; 20545331Samw zct.zct_props = nvprops; 20555331Samw 20562676Seschrock if (zc->zc_value[0] != '\0') { 2057789Sahrens /* 2058789Sahrens * We're creating a clone of an existing snapshot. 2059789Sahrens */ 20602676Seschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 20612676Seschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 20624543Smarks nvlist_free(nvprops); 2063789Sahrens return (EINVAL); 20642676Seschrock } 2065789Sahrens 20662676Seschrock error = dmu_objset_open(zc->zc_value, type, 20676689Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 20682676Seschrock if (error) { 20694543Smarks nvlist_free(nvprops); 2070789Sahrens return (error); 20712676Seschrock } 20726492Stimh 20736492Stimh error = dmu_objset_create(zc->zc_name, type, clone, 0, 20746492Stimh NULL, NULL); 20755331Samw if (error) { 20765331Samw dmu_objset_close(clone); 20775331Samw nvlist_free(nvprops); 20785331Samw return (error); 20795331Samw } 2080789Sahrens dmu_objset_close(clone); 2081789Sahrens } else { 20826492Stimh boolean_t is_insensitive = B_FALSE; 20836492Stimh 20842676Seschrock if (cbfunc == NULL) { 20854543Smarks nvlist_free(nvprops); 20862199Sahrens return (EINVAL); 20872676Seschrock } 20882676Seschrock 2089789Sahrens if (type == DMU_OST_ZVOL) { 20902676Seschrock uint64_t volsize, volblocksize; 20912676Seschrock 20924543Smarks if (nvprops == NULL || 20934543Smarks nvlist_lookup_uint64(nvprops, 20942676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 20952676Seschrock &volsize) != 0) { 20964543Smarks nvlist_free(nvprops); 20972676Seschrock return (EINVAL); 20982676Seschrock } 20992676Seschrock 21004543Smarks if ((error = nvlist_lookup_uint64(nvprops, 21012676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 21022676Seschrock &volblocksize)) != 0 && error != ENOENT) { 21034543Smarks nvlist_free(nvprops); 21042676Seschrock return (EINVAL); 21052676Seschrock } 21061133Seschrock 21072676Seschrock if (error != 0) 21082676Seschrock volblocksize = zfs_prop_default_numeric( 21092676Seschrock ZFS_PROP_VOLBLOCKSIZE); 21102676Seschrock 21112676Seschrock if ((error = zvol_check_volblocksize( 21122676Seschrock volblocksize)) != 0 || 21132676Seschrock (error = zvol_check_volsize(volsize, 21142676Seschrock volblocksize)) != 0) { 21154543Smarks nvlist_free(nvprops); 2116789Sahrens return (error); 21172676Seschrock } 21184577Sahrens } else if (type == DMU_OST_ZFS) { 21195331Samw int error; 21205331Samw 21215498Stimh /* 21225331Samw * We have to have normalization and 21235331Samw * case-folding flags correct when we do the 21245331Samw * file system creation, so go figure them out 21255498Stimh * now. 21265331Samw */ 21275498Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 21285498Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 21295498Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 21307184Stimh zct.zct_zplprops, &is_insensitive); 21315331Samw if (error != 0) { 21325331Samw nvlist_free(nvprops); 21335498Stimh nvlist_free(zct.zct_zplprops); 21345331Samw return (error); 21354577Sahrens } 21362676Seschrock } 21376492Stimh error = dmu_objset_create(zc->zc_name, type, NULL, 21386492Stimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 21395498Stimh nvlist_free(zct.zct_zplprops); 2140789Sahrens } 21412676Seschrock 21422676Seschrock /* 21432676Seschrock * It would be nice to do this atomically. 21442676Seschrock */ 21452676Seschrock if (error == 0) { 21464787Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 21472676Seschrock (void) dmu_objset_destroy(zc->zc_name); 21482676Seschrock } 21494543Smarks nvlist_free(nvprops); 2150789Sahrens return (error); 2151789Sahrens } 2152789Sahrens 21537265Sahrens struct snap_prop_arg { 21547265Sahrens nvlist_t *nvprops; 21557265Sahrens const char *snapname; 21567265Sahrens }; 21577265Sahrens 21587265Sahrens static int 21597265Sahrens set_snap_props(char *name, void *arg) 21607265Sahrens { 21617265Sahrens struct snap_prop_arg *snpa = arg; 21627265Sahrens int len = strlen(name) + strlen(snpa->snapname) + 2; 21637265Sahrens char *buf = kmem_alloc(len, KM_SLEEP); 21647265Sahrens int err; 21657265Sahrens 21667265Sahrens (void) snprintf(buf, len, "%s@%s", name, snpa->snapname); 21677265Sahrens err = zfs_set_prop_nvlist(buf, snpa->nvprops); 21687265Sahrens if (err) 21697265Sahrens (void) dmu_objset_destroy(buf); 21707265Sahrens kmem_free(buf, len); 21717265Sahrens return (err); 21727265Sahrens } 21737265Sahrens 21745367Sahrens /* 21755367Sahrens * inputs: 21765367Sahrens * zc_name name of filesystem 21775367Sahrens * zc_value short name of snapshot 21785367Sahrens * zc_cookie recursive flag 21795367Sahrens * 21805367Sahrens * outputs: none 21815367Sahrens */ 2182789Sahrens static int 21832199Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 21842199Sahrens { 21857265Sahrens nvlist_t *nvprops = NULL; 21867265Sahrens int error; 21877265Sahrens boolean_t recursive = zc->zc_cookie; 21887265Sahrens 21892676Seschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 21902199Sahrens return (EINVAL); 21917265Sahrens 21927265Sahrens if (zc->zc_nvlist_src != NULL && 21937265Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 21947265Sahrens &nvprops)) != 0) 21957265Sahrens return (error); 21967265Sahrens 21977265Sahrens error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, recursive); 21987265Sahrens 21997265Sahrens /* 22007265Sahrens * It would be nice to do this atomically. 22017265Sahrens */ 22027265Sahrens if (error == 0) { 22037265Sahrens struct snap_prop_arg snpa; 22047265Sahrens snpa.nvprops = nvprops; 22057265Sahrens snpa.snapname = zc->zc_value; 22067265Sahrens if (recursive) { 22077265Sahrens error = dmu_objset_find(zc->zc_name, 22087265Sahrens set_snap_props, &snpa, DS_FIND_CHILDREN); 22097265Sahrens if (error) { 22107265Sahrens (void) dmu_snapshots_destroy(zc->zc_name, 22117265Sahrens zc->zc_value); 22127265Sahrens } 22137265Sahrens } else { 22147265Sahrens error = set_snap_props(zc->zc_name, &snpa); 22157265Sahrens } 22167265Sahrens } 22177265Sahrens nvlist_free(nvprops); 22187265Sahrens return (error); 22192199Sahrens } 22202199Sahrens 22214007Smmusante int 22222199Sahrens zfs_unmount_snap(char *name, void *arg) 2223789Sahrens { 22242417Sahrens vfs_t *vfsp = NULL; 22252199Sahrens 22266689Smaybee if (arg) { 22276689Smaybee char *snapname = arg; 22286689Smaybee int len = strlen(name) + strlen(snapname) + 2; 22296689Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 22306689Smaybee 22316689Smaybee (void) strcpy(buf, name); 22326689Smaybee (void) strcat(buf, "@"); 22336689Smaybee (void) strcat(buf, snapname); 22346689Smaybee vfsp = zfs_get_vfs(buf); 22356689Smaybee kmem_free(buf, len); 22362417Sahrens } else if (strchr(name, '@')) { 22372199Sahrens vfsp = zfs_get_vfs(name); 22382199Sahrens } 22392199Sahrens 22402199Sahrens if (vfsp) { 22412199Sahrens /* 22422199Sahrens * Always force the unmount for snapshots. 22432199Sahrens */ 22442199Sahrens int flag = MS_FORCE; 2245789Sahrens int err; 2246789Sahrens 22472199Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 22482199Sahrens VFS_RELE(vfsp); 22492199Sahrens return (err); 22502199Sahrens } 22512199Sahrens VFS_RELE(vfsp); 22522199Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 22532199Sahrens return (err); 22542199Sahrens } 22552199Sahrens return (0); 22562199Sahrens } 22572199Sahrens 22585367Sahrens /* 22595367Sahrens * inputs: 22605367Sahrens * zc_name name of filesystem 22615367Sahrens * zc_value short name of snapshot 22625367Sahrens * 22635367Sahrens * outputs: none 22645367Sahrens */ 22652199Sahrens static int 22662199Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 22672199Sahrens { 22682199Sahrens int err; 2269789Sahrens 22702676Seschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 22712199Sahrens return (EINVAL); 22722199Sahrens err = dmu_objset_find(zc->zc_name, 22732676Seschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 22742199Sahrens if (err) 22752199Sahrens return (err); 22762676Seschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 22772199Sahrens } 22782199Sahrens 22795367Sahrens /* 22805367Sahrens * inputs: 22815367Sahrens * zc_name name of dataset to destroy 22825367Sahrens * zc_objset_type type of objset 22835367Sahrens * 22845367Sahrens * outputs: none 22855367Sahrens */ 22862199Sahrens static int 22872199Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 22882199Sahrens { 22892199Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 22902199Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 22912199Sahrens if (err) 22922199Sahrens return (err); 2293789Sahrens } 2294789Sahrens 2295789Sahrens return (dmu_objset_destroy(zc->zc_name)); 2296789Sahrens } 2297789Sahrens 22985367Sahrens /* 22995367Sahrens * inputs: 23005446Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 23015367Sahrens * 23025367Sahrens * outputs: none 23035367Sahrens */ 2304789Sahrens static int 2305789Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2306789Sahrens { 23075446Sahrens objset_t *os; 23085446Sahrens int error; 23095446Sahrens zfsvfs_t *zfsvfs = NULL; 23105446Sahrens 23115446Sahrens /* 23125446Sahrens * Get the zfsvfs for the receiving objset. There 23135446Sahrens * won't be one if we're operating on a zvol, if the 23145446Sahrens * objset doesn't exist yet, or is not mounted. 23155446Sahrens */ 23166689Smaybee error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, DS_MODE_USER, &os); 23175446Sahrens if (error) 23185446Sahrens return (error); 23195446Sahrens 23205446Sahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 23215446Sahrens mutex_enter(&os->os->os_user_ptr_lock); 23225446Sahrens zfsvfs = dmu_objset_get_user(os); 23235446Sahrens if (zfsvfs != NULL) 23245446Sahrens VFS_HOLD(zfsvfs->z_vfs); 23255446Sahrens mutex_exit(&os->os->os_user_ptr_lock); 23265446Sahrens } 23275446Sahrens 23285446Sahrens if (zfsvfs != NULL) { 23298012SEric.Taylor@Sun.COM char *osname; 23305446Sahrens int mode; 23315446Sahrens 23328012SEric.Taylor@Sun.COM osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 23336083Sek110237 error = zfs_suspend_fs(zfsvfs, osname, &mode); 23346083Sek110237 if (error == 0) { 23356083Sek110237 int resume_err; 23366083Sek110237 23376083Sek110237 ASSERT(strcmp(osname, zc->zc_name) == 0); 23386083Sek110237 error = dmu_objset_rollback(os); 23396083Sek110237 resume_err = zfs_resume_fs(zfsvfs, osname, mode); 23406083Sek110237 error = error ? error : resume_err; 23416083Sek110237 } else { 23426083Sek110237 dmu_objset_close(os); 23436083Sek110237 } 23448012SEric.Taylor@Sun.COM kmem_free(osname, MAXNAMELEN); 23455446Sahrens VFS_RELE(zfsvfs->z_vfs); 23465446Sahrens } else { 23475446Sahrens error = dmu_objset_rollback(os); 23485446Sahrens } 23496689Smaybee /* Note, the dmu_objset_rollback() releases the objset for us. */ 23505446Sahrens 23515446Sahrens return (error); 2352789Sahrens } 2353789Sahrens 23545367Sahrens /* 23555367Sahrens * inputs: 23565367Sahrens * zc_name old name of dataset 23575367Sahrens * zc_value new name of dataset 23585367Sahrens * zc_cookie recursive flag (only valid for snapshots) 23595367Sahrens * 23605367Sahrens * outputs: none 23615367Sahrens */ 2362789Sahrens static int 2363789Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2364789Sahrens { 23654490Svb160487 boolean_t recursive = zc->zc_cookie & 1; 23664007Smmusante 23672676Seschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 23685326Sek110237 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 23695326Sek110237 strchr(zc->zc_value, '%')) 2370789Sahrens return (EINVAL); 2371789Sahrens 23724007Smmusante /* 23734007Smmusante * Unmount snapshot unless we're doing a recursive rename, 23744007Smmusante * in which case the dataset code figures out which snapshots 23754007Smmusante * to unmount. 23764007Smmusante */ 23774007Smmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2378789Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 23792199Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 23802199Sahrens if (err) 23812199Sahrens return (err); 2382789Sahrens } 23834007Smmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2384789Sahrens } 2385789Sahrens 23866689Smaybee static void 23876689Smaybee clear_props(char *dataset, nvlist_t *props) 23886689Smaybee { 23896689Smaybee zfs_cmd_t *zc; 23906689Smaybee nvpair_t *prop; 23916689Smaybee 23926689Smaybee if (props == NULL) 23936689Smaybee return; 23946689Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 23956689Smaybee (void) strcpy(zc->zc_name, dataset); 23966689Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 23976689Smaybee prop = nvlist_next_nvpair(props, prop)) { 23986689Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 23996689Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 24006689Smaybee (void) zfs_ioc_inherit_prop(zc); 24016689Smaybee } 24026689Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 24036689Smaybee } 24046689Smaybee 24055367Sahrens /* 24065367Sahrens * inputs: 24075367Sahrens * zc_name name of containing filesystem 24085367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 24095367Sahrens * zc_value name of snapshot to create 24105367Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 24115367Sahrens * zc_cookie file descriptor to recv from 24125367Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 24135367Sahrens * zc_guid force flag 24145367Sahrens * 24155367Sahrens * outputs: 24165367Sahrens * zc_cookie number of bytes read 24175367Sahrens */ 2418789Sahrens static int 24195367Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2420789Sahrens { 2421789Sahrens file_t *fp; 24225326Sek110237 objset_t *os; 24235367Sahrens dmu_recv_cookie_t drc; 24245326Sek110237 zfsvfs_t *zfsvfs = NULL; 24255326Sek110237 boolean_t force = (boolean_t)zc->zc_guid; 2426789Sahrens int error, fd; 24275367Sahrens offset_t off; 24285367Sahrens nvlist_t *props = NULL; 24296689Smaybee nvlist_t *origprops = NULL; 24305367Sahrens objset_t *origin = NULL; 24315367Sahrens char *tosnap; 24325367Sahrens char tofs[ZFS_MAXNAMELEN]; 2433789Sahrens 24343265Sahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 24355326Sek110237 strchr(zc->zc_value, '@') == NULL || 24365326Sek110237 strchr(zc->zc_value, '%')) 24373265Sahrens return (EINVAL); 24383265Sahrens 24395367Sahrens (void) strcpy(tofs, zc->zc_value); 24405367Sahrens tosnap = strchr(tofs, '@'); 24415367Sahrens *tosnap = '\0'; 24425367Sahrens tosnap++; 24435367Sahrens 24445367Sahrens if (zc->zc_nvlist_src != NULL && 24455367Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 24465367Sahrens &props)) != 0) 24475367Sahrens return (error); 24485367Sahrens 2449789Sahrens fd = zc->zc_cookie; 2450789Sahrens fp = getf(fd); 24515367Sahrens if (fp == NULL) { 24525367Sahrens nvlist_free(props); 2453789Sahrens return (EBADF); 24545367Sahrens } 24555326Sek110237 24566689Smaybee if (dmu_objset_open(tofs, DMU_OST_ANY, 24576689Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 24586689Smaybee /* 24596689Smaybee * Try to get the zfsvfs for the receiving objset. 24606689Smaybee * There won't be one if we're operating on a zvol, 24616689Smaybee * if the objset doesn't exist yet, or is not mounted. 24626689Smaybee */ 24635446Sahrens mutex_enter(&os->os->os_user_ptr_lock); 24646689Smaybee if (zfsvfs = dmu_objset_get_user(os)) { 24656083Sek110237 if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) { 24666689Smaybee mutex_exit(&os->os->os_user_ptr_lock); 24676083Sek110237 dmu_objset_close(os); 24686689Smaybee zfsvfs = NULL; 24696689Smaybee error = EBUSY; 24706689Smaybee goto out; 24716083Sek110237 } 24726689Smaybee VFS_HOLD(zfsvfs->z_vfs); 24736083Sek110237 } 24746689Smaybee mutex_exit(&os->os->os_user_ptr_lock); 24756689Smaybee 24766689Smaybee /* 24776689Smaybee * If new properties are supplied, they are to completely 24786689Smaybee * replace the existing ones, so stash away the existing ones. 24796689Smaybee */ 24806689Smaybee if (props) 24816689Smaybee (void) dsl_prop_get_all(os, &origprops, TRUE); 24826689Smaybee 24835326Sek110237 dmu_objset_close(os); 24845326Sek110237 } 24855326Sek110237 24865367Sahrens if (zc->zc_string[0]) { 24875367Sahrens error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 24886689Smaybee DS_MODE_USER | DS_MODE_READONLY, &origin); 24896689Smaybee if (error) 24906689Smaybee goto out; 24915367Sahrens } 24925367Sahrens 24935367Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 24945367Sahrens force, origin, zfsvfs != NULL, &drc); 24955367Sahrens if (origin) 24965367Sahrens dmu_objset_close(origin); 24976689Smaybee if (error) 24986689Smaybee goto out; 24995326Sek110237 25005326Sek110237 /* 25016689Smaybee * Reset properties. We do this before we receive the stream 25026689Smaybee * so that the properties are applied to the new data. 25035326Sek110237 */ 25045367Sahrens if (props) { 25056689Smaybee clear_props(tofs, origprops); 25066689Smaybee /* 25076689Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 25086689Smaybee */ 25096689Smaybee (void) zfs_set_prop_nvlist(tofs, props); 25105367Sahrens } 25115367Sahrens 25125367Sahrens off = fp->f_offset; 25135367Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 25145367Sahrens 25156689Smaybee if (error == 0 && zfsvfs) { 25168012SEric.Taylor@Sun.COM char *osname; 25176689Smaybee int mode; 25186689Smaybee 25196689Smaybee /* online recv */ 25208012SEric.Taylor@Sun.COM osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 25216689Smaybee error = zfs_suspend_fs(zfsvfs, osname, &mode); 25226689Smaybee if (error == 0) { 25236689Smaybee int resume_err; 25246689Smaybee 25256689Smaybee error = dmu_recv_end(&drc); 25266689Smaybee resume_err = zfs_resume_fs(zfsvfs, osname, mode); 25276689Smaybee error = error ? error : resume_err; 25285367Sahrens } else { 25296689Smaybee dmu_recv_abort_cleanup(&drc); 25305367Sahrens } 25318012SEric.Taylor@Sun.COM kmem_free(osname, MAXNAMELEN); 25326689Smaybee } else if (error == 0) { 25336689Smaybee error = dmu_recv_end(&drc); 25346083Sek110237 } 25355367Sahrens 25365367Sahrens zc->zc_cookie = off - fp->f_offset; 25375367Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 25385367Sahrens fp->f_offset = off; 25392885Sahrens 25406689Smaybee /* 25416689Smaybee * On error, restore the original props. 25426689Smaybee */ 25436689Smaybee if (error && props) { 25446689Smaybee clear_props(tofs, props); 25456689Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 25466689Smaybee } 25476689Smaybee out: 25486689Smaybee if (zfsvfs) { 25496689Smaybee mutex_exit(&zfsvfs->z_online_recv_lock); 25506689Smaybee VFS_RELE(zfsvfs->z_vfs); 25516689Smaybee } 25526689Smaybee nvlist_free(props); 25536689Smaybee nvlist_free(origprops); 2554789Sahrens releasef(fd); 2555789Sahrens return (error); 2556789Sahrens } 2557789Sahrens 25585367Sahrens /* 25595367Sahrens * inputs: 25605367Sahrens * zc_name name of snapshot to send 25615367Sahrens * zc_value short name of incremental fromsnap (may be empty) 25625367Sahrens * zc_cookie file descriptor to send stream to 25635367Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 25645367Sahrens * 25655367Sahrens * outputs: none 25665367Sahrens */ 2567789Sahrens static int 25685367Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2569789Sahrens { 2570789Sahrens objset_t *fromsnap = NULL; 2571789Sahrens objset_t *tosnap; 2572789Sahrens file_t *fp; 2573789Sahrens int error; 25745367Sahrens offset_t off; 2575789Sahrens 2576789Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 25776689Smaybee DS_MODE_USER | DS_MODE_READONLY, &tosnap); 2578789Sahrens if (error) 2579789Sahrens return (error); 2580789Sahrens 25812676Seschrock if (zc->zc_value[0] != '\0') { 25828012SEric.Taylor@Sun.COM char *buf; 25832885Sahrens char *cp; 25842885Sahrens 25858012SEric.Taylor@Sun.COM buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 25868012SEric.Taylor@Sun.COM (void) strncpy(buf, zc->zc_name, MAXPATHLEN); 25872885Sahrens cp = strchr(buf, '@'); 25882885Sahrens if (cp) 25892885Sahrens *(cp+1) = 0; 25908012SEric.Taylor@Sun.COM (void) strncat(buf, zc->zc_value, MAXPATHLEN); 25912885Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 25926689Smaybee DS_MODE_USER | DS_MODE_READONLY, &fromsnap); 25938012SEric.Taylor@Sun.COM kmem_free(buf, MAXPATHLEN); 2594789Sahrens if (error) { 2595789Sahrens dmu_objset_close(tosnap); 2596789Sahrens return (error); 2597789Sahrens } 2598789Sahrens } 2599789Sahrens 2600789Sahrens fp = getf(zc->zc_cookie); 2601789Sahrens if (fp == NULL) { 2602789Sahrens dmu_objset_close(tosnap); 2603789Sahrens if (fromsnap) 2604789Sahrens dmu_objset_close(fromsnap); 2605789Sahrens return (EBADF); 2606789Sahrens } 2607789Sahrens 26085367Sahrens off = fp->f_offset; 26095367Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 26105367Sahrens 26115367Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 26125367Sahrens fp->f_offset = off; 2613789Sahrens releasef(zc->zc_cookie); 2614789Sahrens if (fromsnap) 2615789Sahrens dmu_objset_close(fromsnap); 2616789Sahrens dmu_objset_close(tosnap); 2617789Sahrens return (error); 2618789Sahrens } 2619789Sahrens 26201544Seschrock static int 26211544Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 26221544Seschrock { 26231544Seschrock int id, error; 26241544Seschrock 26251544Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 26261544Seschrock &zc->zc_inject_record); 26271544Seschrock 26281544Seschrock if (error == 0) 26291544Seschrock zc->zc_guid = (uint64_t)id; 26301544Seschrock 26311544Seschrock return (error); 26321544Seschrock } 26331544Seschrock 26341544Seschrock static int 26351544Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 26361544Seschrock { 26371544Seschrock return (zio_clear_fault((int)zc->zc_guid)); 26381544Seschrock } 26391544Seschrock 26401544Seschrock static int 26411544Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 26421544Seschrock { 26431544Seschrock int id = (int)zc->zc_guid; 26441544Seschrock int error; 26451544Seschrock 26461544Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 26471544Seschrock &zc->zc_inject_record); 26481544Seschrock 26491544Seschrock zc->zc_guid = id; 26501544Seschrock 26511544Seschrock return (error); 26521544Seschrock } 26531544Seschrock 26541544Seschrock static int 26551544Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 26561544Seschrock { 26571544Seschrock spa_t *spa; 26581544Seschrock int error; 26592676Seschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 26601544Seschrock 26611544Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 26621544Seschrock return (error); 26631544Seschrock 26642676Seschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 26651544Seschrock &count); 26661544Seschrock if (error == 0) 26672676Seschrock zc->zc_nvlist_dst_size = count; 26681544Seschrock else 26692676Seschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 26701544Seschrock 26711544Seschrock spa_close(spa, FTAG); 26721544Seschrock 26731544Seschrock return (error); 26741544Seschrock } 26751544Seschrock 26761544Seschrock static int 26771544Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 26781544Seschrock { 26791544Seschrock spa_t *spa; 26801544Seschrock vdev_t *vd; 26811544Seschrock int error; 26821544Seschrock 26837294Sperrin /* 26847294Sperrin * On zpool clear we also fix up missing slogs 26857294Sperrin */ 26867294Sperrin mutex_enter(&spa_namespace_lock); 26877294Sperrin spa = spa_lookup(zc->zc_name); 26887294Sperrin if (spa == NULL) { 26897294Sperrin mutex_exit(&spa_namespace_lock); 26907294Sperrin return (EIO); 26917294Sperrin } 26927294Sperrin if (spa->spa_log_state == SPA_LOG_MISSING) { 26937294Sperrin /* we need to let spa_open/spa_load clear the chains */ 26947294Sperrin spa->spa_log_state = SPA_LOG_CLEAR; 26957294Sperrin } 26967294Sperrin mutex_exit(&spa_namespace_lock); 26977294Sperrin 26981544Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 26991544Seschrock return (error); 27001544Seschrock 27017754SJeff.Bonwick@Sun.COM spa_vdev_state_enter(spa); 27021544Seschrock 27032676Seschrock if (zc->zc_guid == 0) { 27041544Seschrock vd = NULL; 27056643Seschrock } else { 27066643Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 27075450Sbrendan if (vd == NULL) { 27087754SJeff.Bonwick@Sun.COM (void) spa_vdev_state_exit(spa, NULL, ENODEV); 27095450Sbrendan spa_close(spa, FTAG); 27105450Sbrendan return (ENODEV); 27115450Sbrendan } 27121544Seschrock } 27131544Seschrock 27147754SJeff.Bonwick@Sun.COM vdev_clear(spa, vd); 27157754SJeff.Bonwick@Sun.COM 27167754SJeff.Bonwick@Sun.COM (void) spa_vdev_state_exit(spa, NULL, 0); 27177754SJeff.Bonwick@Sun.COM 27187754SJeff.Bonwick@Sun.COM /* 27197754SJeff.Bonwick@Sun.COM * Resume any suspended I/Os. 27207754SJeff.Bonwick@Sun.COM */ 27217754SJeff.Bonwick@Sun.COM zio_resume(spa); 27221544Seschrock 27231544Seschrock spa_close(spa, FTAG); 27241544Seschrock 27251544Seschrock return (0); 27261544Seschrock } 27271544Seschrock 27285367Sahrens /* 27295367Sahrens * inputs: 27305367Sahrens * zc_name name of filesystem 27315367Sahrens * zc_value name of origin snapshot 27325367Sahrens * 27335367Sahrens * outputs: none 27345367Sahrens */ 27351544Seschrock static int 27362082Seschrock zfs_ioc_promote(zfs_cmd_t *zc) 27372082Seschrock { 27382417Sahrens char *cp; 27392417Sahrens 27402417Sahrens /* 27412417Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 27422417Sahrens * it's easier. 27432417Sahrens */ 27442676Seschrock cp = strchr(zc->zc_value, '@'); 27452417Sahrens if (cp) 27462417Sahrens *cp = '\0'; 27472676Seschrock (void) dmu_objset_find(zc->zc_value, 27482417Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 27492082Seschrock return (dsl_dataset_promote(zc->zc_name)); 27502082Seschrock } 27512082Seschrock 27524543Smarks /* 27534543Smarks * We don't want to have a hard dependency 27544543Smarks * against some special symbols in sharefs 27555331Samw * nfs, and smbsrv. Determine them if needed when 27564543Smarks * the first file system is shared. 27575331Samw * Neither sharefs, nfs or smbsrv are unloadable modules. 27584543Smarks */ 27595331Samw int (*znfsexport_fs)(void *arg); 27604543Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 27615331Samw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 27625331Samw 27635331Samw int zfs_nfsshare_inited; 27645331Samw int zfs_smbshare_inited; 27655331Samw 27664543Smarks ddi_modhandle_t nfs_mod; 27674543Smarks ddi_modhandle_t sharefs_mod; 27685331Samw ddi_modhandle_t smbsrv_mod; 27694543Smarks kmutex_t zfs_share_lock; 27704543Smarks 27714543Smarks static int 27725331Samw zfs_init_sharefs() 27735331Samw { 27745331Samw int error; 27755331Samw 27765331Samw ASSERT(MUTEX_HELD(&zfs_share_lock)); 27775331Samw /* Both NFS and SMB shares also require sharetab support. */ 27785331Samw if (sharefs_mod == NULL && ((sharefs_mod = 27795331Samw ddi_modopen("fs/sharefs", 27805331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 27815331Samw return (ENOSYS); 27825331Samw } 27835331Samw if (zshare_fs == NULL && ((zshare_fs = 27845331Samw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 27855331Samw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 27865331Samw return (ENOSYS); 27875331Samw } 27885331Samw return (0); 27895331Samw } 27905331Samw 27915331Samw static int 27924543Smarks zfs_ioc_share(zfs_cmd_t *zc) 27934543Smarks { 27944543Smarks int error; 27954543Smarks int opcode; 27964543Smarks 27975331Samw switch (zc->zc_share.z_sharetype) { 27985331Samw case ZFS_SHARE_NFS: 27995331Samw case ZFS_UNSHARE_NFS: 28005331Samw if (zfs_nfsshare_inited == 0) { 28015331Samw mutex_enter(&zfs_share_lock); 28025331Samw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 28035331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 28045331Samw mutex_exit(&zfs_share_lock); 28055331Samw return (ENOSYS); 28065331Samw } 28075331Samw if (znfsexport_fs == NULL && 28085331Samw ((znfsexport_fs = (int (*)(void *)) 28095331Samw ddi_modsym(nfs_mod, 28105331Samw "nfs_export", &error)) == NULL)) { 28115331Samw mutex_exit(&zfs_share_lock); 28125331Samw return (ENOSYS); 28135331Samw } 28145331Samw error = zfs_init_sharefs(); 28155331Samw if (error) { 28165331Samw mutex_exit(&zfs_share_lock); 28175331Samw return (ENOSYS); 28185331Samw } 28195331Samw zfs_nfsshare_inited = 1; 28204543Smarks mutex_exit(&zfs_share_lock); 28214543Smarks } 28225331Samw break; 28235331Samw case ZFS_SHARE_SMB: 28245331Samw case ZFS_UNSHARE_SMB: 28255331Samw if (zfs_smbshare_inited == 0) { 28265331Samw mutex_enter(&zfs_share_lock); 28275331Samw if (smbsrv_mod == NULL && ((smbsrv_mod = 28285331Samw ddi_modopen("drv/smbsrv", 28295331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 28305331Samw mutex_exit(&zfs_share_lock); 28315331Samw return (ENOSYS); 28325331Samw } 28335331Samw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 28345331Samw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 28356139Sjb150015 "smb_server_share", &error)) == NULL)) { 28365331Samw mutex_exit(&zfs_share_lock); 28375331Samw return (ENOSYS); 28385331Samw } 28395331Samw error = zfs_init_sharefs(); 28405331Samw if (error) { 28415331Samw mutex_exit(&zfs_share_lock); 28425331Samw return (ENOSYS); 28435331Samw } 28445331Samw zfs_smbshare_inited = 1; 28454543Smarks mutex_exit(&zfs_share_lock); 28464543Smarks } 28475331Samw break; 28485331Samw default: 28495331Samw return (EINVAL); 28504543Smarks } 28514543Smarks 28525331Samw switch (zc->zc_share.z_sharetype) { 28535331Samw case ZFS_SHARE_NFS: 28545331Samw case ZFS_UNSHARE_NFS: 28555331Samw if (error = 28565331Samw znfsexport_fs((void *) 28575331Samw (uintptr_t)zc->zc_share.z_exportdata)) 28585331Samw return (error); 28595331Samw break; 28605331Samw case ZFS_SHARE_SMB: 28615331Samw case ZFS_UNSHARE_SMB: 28625331Samw if (error = zsmbexport_fs((void *) 28635331Samw (uintptr_t)zc->zc_share.z_exportdata, 28645331Samw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 28655331Samw B_TRUE : B_FALSE)) { 28665331Samw return (error); 28675331Samw } 28685331Samw break; 28695331Samw } 28705331Samw 28715331Samw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 28725331Samw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 28734543Smarks SHAREFS_ADD : SHAREFS_REMOVE; 28744543Smarks 28755331Samw /* 28765331Samw * Add or remove share from sharetab 28775331Samw */ 28784543Smarks error = zshare_fs(opcode, 28794543Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 28804543Smarks zc->zc_share.z_sharemax); 28814543Smarks 28824543Smarks return (error); 28834543Smarks 28844543Smarks } 28854543Smarks 28864543Smarks /* 28874988Sek110237 * pool create, destroy, and export don't log the history as part of 28884988Sek110237 * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 28894988Sek110237 * do the logging of those commands. 28904543Smarks */ 2891789Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 28924715Sek110237 { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28934577Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28944577Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 28954577Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 28964577Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 28974577Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 28984577Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 28994577Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29004577Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 29014577Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29024577Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 29034577Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29044577Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29054577Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29064577Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29074577Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29084577Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 29094577Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 29105498Stimh { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 29114543Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 29124577Sahrens DATASET_NAME, B_FALSE }, 29134543Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 29144577Sahrens DATASET_NAME, B_FALSE }, 29154577Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 29164577Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 29174577Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 29184577Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 29194577Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 29204577Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 29214577Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 29225367Sahrens { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 29235367Sahrens { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 29244577Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 29254577Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 29264577Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 29274577Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 29284577Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29294577Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 29304577Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 29314577Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 29324577Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 29334577Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 29344577Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 29354577Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 29364577Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 29374577Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 29384543Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 29394577Sahrens DATASET_NAME, B_FALSE }, 29404849Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 29414849Sahrens { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 2942789Sahrens }; 2943789Sahrens 2944789Sahrens static int 2945789Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2946789Sahrens { 2947789Sahrens zfs_cmd_t *zc; 2948789Sahrens uint_t vec; 29492199Sahrens int error, rc; 2950789Sahrens 2951789Sahrens if (getminor(dev) != 0) 2952789Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2953789Sahrens 2954789Sahrens vec = cmd - ZFS_IOC; 29554787Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 2956789Sahrens 2957789Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2958789Sahrens return (EINVAL); 2959789Sahrens 2960789Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2961789Sahrens 2962789Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2963789Sahrens 29644787Sahrens if (error == 0) 29654543Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2966789Sahrens 2967789Sahrens /* 2968789Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2969789Sahrens * the lower layers. 2970789Sahrens */ 2971789Sahrens if (error == 0) { 2972789Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2973789Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 29744577Sahrens case POOL_NAME: 2975789Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2976789Sahrens error = EINVAL; 2977789Sahrens break; 2978789Sahrens 29794577Sahrens case DATASET_NAME: 2980789Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2981789Sahrens error = EINVAL; 2982789Sahrens break; 29832856Snd150628 29844577Sahrens case NO_NAME: 29852856Snd150628 break; 2986789Sahrens } 2987789Sahrens } 2988789Sahrens 2989789Sahrens if (error == 0) 2990789Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2991789Sahrens 29922199Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 29934543Smarks if (error == 0) { 29942199Sahrens error = rc; 29954543Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 29964543Smarks zfs_log_history(zc); 29974543Smarks } 2998789Sahrens 2999789Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 3000789Sahrens return (error); 3001789Sahrens } 3002789Sahrens 3003789Sahrens static int 3004789Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3005789Sahrens { 3006789Sahrens if (cmd != DDI_ATTACH) 3007789Sahrens return (DDI_FAILURE); 3008789Sahrens 3009789Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 3010789Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 3011789Sahrens return (DDI_FAILURE); 3012789Sahrens 3013789Sahrens zfs_dip = dip; 3014789Sahrens 3015789Sahrens ddi_report_dev(dip); 3016789Sahrens 3017789Sahrens return (DDI_SUCCESS); 3018789Sahrens } 3019789Sahrens 3020789Sahrens static int 3021789Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3022789Sahrens { 3023789Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 3024789Sahrens return (DDI_FAILURE); 3025789Sahrens 3026789Sahrens if (cmd != DDI_DETACH) 3027789Sahrens return (DDI_FAILURE); 3028789Sahrens 3029789Sahrens zfs_dip = NULL; 3030789Sahrens 3031789Sahrens ddi_prop_remove_all(dip); 3032789Sahrens ddi_remove_minor_node(dip, NULL); 3033789Sahrens 3034789Sahrens return (DDI_SUCCESS); 3035789Sahrens } 3036789Sahrens 3037789Sahrens /*ARGSUSED*/ 3038789Sahrens static int 3039789Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3040789Sahrens { 3041789Sahrens switch (infocmd) { 3042789Sahrens case DDI_INFO_DEVT2DEVINFO: 3043789Sahrens *result = zfs_dip; 3044789Sahrens return (DDI_SUCCESS); 3045789Sahrens 3046789Sahrens case DDI_INFO_DEVT2INSTANCE: 3047849Sbonwick *result = (void *)0; 3048789Sahrens return (DDI_SUCCESS); 3049789Sahrens } 3050789Sahrens 3051789Sahrens return (DDI_FAILURE); 3052789Sahrens } 3053789Sahrens 3054789Sahrens /* 3055789Sahrens * OK, so this is a little weird. 3056789Sahrens * 3057789Sahrens * /dev/zfs is the control node, i.e. minor 0. 3058789Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3059789Sahrens * 3060789Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 3061789Sahrens * so most of the standard driver entry points are in zvol.c. 3062789Sahrens */ 3063789Sahrens static struct cb_ops zfs_cb_ops = { 3064789Sahrens zvol_open, /* open */ 3065789Sahrens zvol_close, /* close */ 3066789Sahrens zvol_strategy, /* strategy */ 3067789Sahrens nodev, /* print */ 30686423Sgw25295 zvol_dump, /* dump */ 3069789Sahrens zvol_read, /* read */ 3070789Sahrens zvol_write, /* write */ 3071789Sahrens zfsdev_ioctl, /* ioctl */ 3072789Sahrens nodev, /* devmap */ 3073789Sahrens nodev, /* mmap */ 3074789Sahrens nodev, /* segmap */ 3075789Sahrens nochpoll, /* poll */ 3076789Sahrens ddi_prop_op, /* prop_op */ 3077789Sahrens NULL, /* streamtab */ 3078789Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 3079789Sahrens CB_REV, /* version */ 30803638Sbillm nodev, /* async read */ 30813638Sbillm nodev, /* async write */ 3082789Sahrens }; 3083789Sahrens 3084789Sahrens static struct dev_ops zfs_dev_ops = { 3085789Sahrens DEVO_REV, /* version */ 3086789Sahrens 0, /* refcnt */ 3087789Sahrens zfs_info, /* info */ 3088789Sahrens nulldev, /* identify */ 3089789Sahrens nulldev, /* probe */ 3090789Sahrens zfs_attach, /* attach */ 3091789Sahrens zfs_detach, /* detach */ 3092789Sahrens nodev, /* reset */ 3093789Sahrens &zfs_cb_ops, /* driver operations */ 30947656SSherry.Moore@Sun.COM NULL, /* no bus operations */ 30957656SSherry.Moore@Sun.COM NULL, /* power */ 30967656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 3097789Sahrens }; 3098789Sahrens 3099789Sahrens static struct modldrv zfs_modldrv = { 31007656SSherry.Moore@Sun.COM &mod_driverops, 31017656SSherry.Moore@Sun.COM "ZFS storage pool", 31027656SSherry.Moore@Sun.COM &zfs_dev_ops 3103789Sahrens }; 3104789Sahrens 3105789Sahrens static struct modlinkage modlinkage = { 3106789Sahrens MODREV_1, 3107789Sahrens (void *)&zfs_modlfs, 3108789Sahrens (void *)&zfs_modldrv, 3109789Sahrens NULL 3110789Sahrens }; 3111789Sahrens 31124720Sfr157268 31134720Sfr157268 uint_t zfs_fsyncer_key; 31145326Sek110237 extern uint_t rrw_tsd_key; 31154720Sfr157268 3116789Sahrens int 3117789Sahrens _init(void) 3118789Sahrens { 3119789Sahrens int error; 3120789Sahrens 3121849Sbonwick spa_init(FREAD | FWRITE); 3122849Sbonwick zfs_init(); 3123849Sbonwick zvol_init(); 3124849Sbonwick 3125849Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 3126849Sbonwick zvol_fini(); 3127849Sbonwick zfs_fini(); 3128849Sbonwick spa_fini(); 3129789Sahrens return (error); 3130849Sbonwick } 3131789Sahrens 31324720Sfr157268 tsd_create(&zfs_fsyncer_key, NULL); 31335326Sek110237 tsd_create(&rrw_tsd_key, NULL); 31344720Sfr157268 3135789Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 3136789Sahrens ASSERT(error == 0); 31374543Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3138789Sahrens 3139789Sahrens return (0); 3140789Sahrens } 3141789Sahrens 3142789Sahrens int 3143789Sahrens _fini(void) 3144789Sahrens { 3145789Sahrens int error; 3146789Sahrens 31471544Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3148789Sahrens return (EBUSY); 3149789Sahrens 3150789Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3151789Sahrens return (error); 3152789Sahrens 3153789Sahrens zvol_fini(); 3154789Sahrens zfs_fini(); 3155789Sahrens spa_fini(); 31565331Samw if (zfs_nfsshare_inited) 31574543Smarks (void) ddi_modclose(nfs_mod); 31585331Samw if (zfs_smbshare_inited) 31595331Samw (void) ddi_modclose(smbsrv_mod); 31605331Samw if (zfs_nfsshare_inited || zfs_smbshare_inited) 31614543Smarks (void) ddi_modclose(sharefs_mod); 3162789Sahrens 31634720Sfr157268 tsd_destroy(&zfs_fsyncer_key); 3164789Sahrens ldi_ident_release(zfs_li); 3165789Sahrens zfs_li = NULL; 31664543Smarks mutex_destroy(&zfs_share_lock); 3167789Sahrens 3168789Sahrens return (error); 3169789Sahrens } 3170789Sahrens 3171789Sahrens int 3172789Sahrens _info(struct modinfo *modinfop) 3173789Sahrens { 3174789Sahrens return (mod_info(&modlinkage, modinfop)); 3175789Sahrens } 3176