1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22379c004dSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/types.h> 27fa9e4066Sahrens #include <sys/param.h> 28fa9e4066Sahrens #include <sys/errno.h> 29fa9e4066Sahrens #include <sys/uio.h> 30fa9e4066Sahrens #include <sys/buf.h> 31fa9e4066Sahrens #include <sys/modctl.h> 32fa9e4066Sahrens #include <sys/open.h> 33fa9e4066Sahrens #include <sys/file.h> 34fa9e4066Sahrens #include <sys/kmem.h> 35fa9e4066Sahrens #include <sys/conf.h> 36fa9e4066Sahrens #include <sys/cmn_err.h> 37fa9e4066Sahrens #include <sys/stat.h> 38fa9e4066Sahrens #include <sys/zfs_ioctl.h> 39da6c28aaSamw #include <sys/zfs_znode.h> 40fa9e4066Sahrens #include <sys/zap.h> 41fa9e4066Sahrens #include <sys/spa.h> 42b1b8ab34Slling #include <sys/spa_impl.h> 43fa9e4066Sahrens #include <sys/vdev.h> 44b1b8ab34Slling #include <sys/vdev_impl.h> 45fa9e4066Sahrens #include <sys/dmu.h> 46fa9e4066Sahrens #include <sys/dsl_dir.h> 47fa9e4066Sahrens #include <sys/dsl_dataset.h> 48fa9e4066Sahrens #include <sys/dsl_prop.h> 49ecd6cf80Smarks #include <sys/dsl_deleg.h> 50ecd6cf80Smarks #include <sys/dmu_objset.h> 51fa9e4066Sahrens #include <sys/ddi.h> 52fa9e4066Sahrens #include <sys/sunddi.h> 53fa9e4066Sahrens #include <sys/sunldi.h> 54fa9e4066Sahrens #include <sys/policy.h> 55fa9e4066Sahrens #include <sys/zone.h> 56fa9e4066Sahrens #include <sys/nvpair.h> 57fa9e4066Sahrens #include <sys/pathname.h> 58fa9e4066Sahrens #include <sys/mount.h> 59fa9e4066Sahrens #include <sys/sdt.h> 60fa9e4066Sahrens #include <sys/fs/zfs.h> 61fa9e4066Sahrens #include <sys/zfs_ctldir.h> 62da6c28aaSamw #include <sys/zfs_dir.h> 63a2eea2e1Sahrens #include <sys/zvol.h> 64ecd6cf80Smarks #include <sharefs/share.h> 65f18faf3fSek #include <sys/dmu_objset.h> 66fa9e4066Sahrens 67fa9e4066Sahrens #include "zfs_namecheck.h" 68e9dbad6fSeschrock #include "zfs_prop.h" 69ecd6cf80Smarks #include "zfs_deleg.h" 70fa9e4066Sahrens 71fa9e4066Sahrens extern struct modlfs zfs_modlfs; 72fa9e4066Sahrens 73fa9e4066Sahrens extern void zfs_init(void); 74fa9e4066Sahrens extern void zfs_fini(void); 75fa9e4066Sahrens 76fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 77fa9e4066Sahrens dev_info_t *zfs_dip; 78fa9e4066Sahrens 79fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 80ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 81fa9e4066Sahrens 8254d692b7SGeorge Wilson typedef enum { 8354d692b7SGeorge Wilson NO_NAME, 8454d692b7SGeorge Wilson POOL_NAME, 8554d692b7SGeorge Wilson DATASET_NAME 8654d692b7SGeorge Wilson } zfs_ioc_namecheck_t; 8754d692b7SGeorge Wilson 88fa9e4066Sahrens typedef struct zfs_ioc_vec { 89fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 90fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 9154d692b7SGeorge Wilson zfs_ioc_namecheck_t zvec_namecheck; 92ecd6cf80Smarks boolean_t zvec_his_log; 9354d692b7SGeorge Wilson boolean_t zvec_pool_check; 94fa9e4066Sahrens } zfs_ioc_vec_t; 95fa9e4066Sahrens 96*14843421SMatthew Ahrens /* This array is indexed by zfs_userquota_prop_t */ 97*14843421SMatthew Ahrens static const char *userquota_perms[] = { 98*14843421SMatthew Ahrens ZFS_DELEG_PERM_USERUSED, 99*14843421SMatthew Ahrens ZFS_DELEG_PERM_USERQUOTA, 100*14843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPUSED, 101*14843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPQUOTA, 102*14843421SMatthew Ahrens }; 103*14843421SMatthew Ahrens 104*14843421SMatthew Ahrens static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 1056e77af0aSDavid Pacheco static void clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops); 1060a48a24eStimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 1070a48a24eStimh boolean_t *); 1080a48a24eStimh int zfs_set_prop_nvlist(const char *, nvlist_t *); 1090a48a24eStimh 110fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 111fa9e4066Sahrens void 112fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 113fa9e4066Sahrens { 114fa9e4066Sahrens const char *newfile; 115fa9e4066Sahrens char buf[256]; 116fa9e4066Sahrens va_list adx; 117fa9e4066Sahrens 118fa9e4066Sahrens /* 119fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 120fa9e4066Sahrens */ 121fa9e4066Sahrens newfile = strrchr(file, '/'); 122fa9e4066Sahrens if (newfile != NULL) { 123fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 124fa9e4066Sahrens } else { 125fa9e4066Sahrens newfile = file; 126fa9e4066Sahrens } 127fa9e4066Sahrens 128fa9e4066Sahrens va_start(adx, fmt); 129fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 130fa9e4066Sahrens va_end(adx); 131fa9e4066Sahrens 132fa9e4066Sahrens /* 133fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 134fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 135fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 136fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 137fa9e4066Sahrens * arg0 = file name 138fa9e4066Sahrens * arg1 = function name 139fa9e4066Sahrens * arg2 = line number 140fa9e4066Sahrens * arg3 = message 141fa9e4066Sahrens */ 142fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 143fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 144fa9e4066Sahrens } 145fa9e4066Sahrens 146ecd6cf80Smarks static void 147228975ccSek history_str_free(char *buf) 148228975ccSek { 149228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 150228975ccSek } 151228975ccSek 152228975ccSek static char * 153228975ccSek history_str_get(zfs_cmd_t *zc) 154ecd6cf80Smarks { 15540feaa91Sahrens char *buf; 156ecd6cf80Smarks 157ecd6cf80Smarks if (zc->zc_history == NULL) 158228975ccSek return (NULL); 159e7437265Sahrens 160ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 161ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 162ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 163228975ccSek history_str_free(buf); 164228975ccSek return (NULL); 165ecd6cf80Smarks } 166ecd6cf80Smarks 167ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 168ecd6cf80Smarks 169228975ccSek return (buf); 170228975ccSek } 171ecd6cf80Smarks 17215e6edf1Sgw /* 17315e6edf1Sgw * Check to see if the named dataset is currently defined as bootable 17415e6edf1Sgw */ 17515e6edf1Sgw static boolean_t 17615e6edf1Sgw zfs_is_bootfs(const char *name) 17715e6edf1Sgw { 17815e6edf1Sgw spa_t *spa; 17915e6edf1Sgw boolean_t ret = B_FALSE; 18015e6edf1Sgw 18115e6edf1Sgw if (spa_open(name, &spa, FTAG) == 0) { 18215e6edf1Sgw if (spa->spa_bootfs) { 18315e6edf1Sgw objset_t *os; 18415e6edf1Sgw 18515e6edf1Sgw if (dmu_objset_open(name, DMU_OST_ZFS, 18615e6edf1Sgw DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 18715e6edf1Sgw ret = (dmu_objset_id(os) == spa->spa_bootfs); 18815e6edf1Sgw dmu_objset_close(os); 18915e6edf1Sgw } 19015e6edf1Sgw } 19115e6edf1Sgw spa_close(spa, FTAG); 19215e6edf1Sgw } 19315e6edf1Sgw return (ret); 19415e6edf1Sgw } 19515e6edf1Sgw 196c2a93d44Stimh /* 1970a48a24eStimh * zfs_earlier_version 198c2a93d44Stimh * 199c2a93d44Stimh * Return non-zero if the spa version is less than requested version. 200c2a93d44Stimh */ 201da6c28aaSamw static int 2020a48a24eStimh zfs_earlier_version(const char *name, int version) 203da6c28aaSamw { 204da6c28aaSamw spa_t *spa; 205da6c28aaSamw 206da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 207da6c28aaSamw if (spa_version(spa) < version) { 208da6c28aaSamw spa_close(spa, FTAG); 209da6c28aaSamw return (1); 210da6c28aaSamw } 211da6c28aaSamw spa_close(spa, FTAG); 212da6c28aaSamw } 213da6c28aaSamw return (0); 214da6c28aaSamw } 215da6c28aaSamw 2169e6eda55Smarks /* 217745cd3c5Smaybee * zpl_earlier_version 2189e6eda55Smarks * 219745cd3c5Smaybee * Return TRUE if the ZPL version is less than requested version. 2209e6eda55Smarks */ 221745cd3c5Smaybee static boolean_t 222745cd3c5Smaybee zpl_earlier_version(const char *name, int version) 2239e6eda55Smarks { 2249e6eda55Smarks objset_t *os; 225745cd3c5Smaybee boolean_t rc = B_TRUE; 2269e6eda55Smarks 2279e6eda55Smarks if (dmu_objset_open(name, DMU_OST_ANY, 228745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 229745cd3c5Smaybee uint64_t zplversion; 2309e6eda55Smarks 231745cd3c5Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 232745cd3c5Smaybee rc = zplversion < version; 2339e6eda55Smarks dmu_objset_close(os); 2349e6eda55Smarks } 2359e6eda55Smarks return (rc); 2369e6eda55Smarks } 2379e6eda55Smarks 238228975ccSek static void 239228975ccSek zfs_log_history(zfs_cmd_t *zc) 240228975ccSek { 241228975ccSek spa_t *spa; 242228975ccSek char *buf; 243ecd6cf80Smarks 244228975ccSek if ((buf = history_str_get(zc)) == NULL) 245228975ccSek return; 246228975ccSek 247228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 248228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 249228975ccSek (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 250228975ccSek spa_close(spa, FTAG); 251228975ccSek } 252228975ccSek history_str_free(buf); 253ecd6cf80Smarks } 254ecd6cf80Smarks 255fa9e4066Sahrens /* 256fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 257fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 258fa9e4066Sahrens */ 259fa9e4066Sahrens /* ARGSUSED */ 260fa9e4066Sahrens static int 261ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 262fa9e4066Sahrens { 263fa9e4066Sahrens return (0); 264fa9e4066Sahrens } 265fa9e4066Sahrens 266fa9e4066Sahrens /* 267fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 268fa9e4066Sahrens * no privileges, but must be visible in the local zone. 269fa9e4066Sahrens */ 270fa9e4066Sahrens /* ARGSUSED */ 271fa9e4066Sahrens static int 272ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 273fa9e4066Sahrens { 274fa9e4066Sahrens if (INGLOBALZONE(curproc) || 275ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 276fa9e4066Sahrens return (0); 277fa9e4066Sahrens 278fa9e4066Sahrens return (ENOENT); 279fa9e4066Sahrens } 280fa9e4066Sahrens 281fa9e4066Sahrens static int 282fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 283fa9e4066Sahrens { 284fa9e4066Sahrens uint64_t zoned; 285fa9e4066Sahrens int writable = 1; 286fa9e4066Sahrens 287fa9e4066Sahrens /* 288fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 289fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 290fa9e4066Sahrens */ 291fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 292fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 293fa9e4066Sahrens return (ENOENT); 294fa9e4066Sahrens 295fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 296fa9e4066Sahrens return (ENOENT); 297fa9e4066Sahrens 298fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 299fa9e4066Sahrens /* 300fa9e4066Sahrens * If the fs is zoned, only root can access it from the 301fa9e4066Sahrens * global zone. 302fa9e4066Sahrens */ 303fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 304fa9e4066Sahrens return (EPERM); 305fa9e4066Sahrens } else { 306fa9e4066Sahrens /* 307fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 308fa9e4066Sahrens */ 309fa9e4066Sahrens if (!zoned) 310fa9e4066Sahrens return (EPERM); 311fa9e4066Sahrens 312fa9e4066Sahrens /* must be writable by this zone */ 313fa9e4066Sahrens if (!writable) 314fa9e4066Sahrens return (EPERM); 315fa9e4066Sahrens } 316fa9e4066Sahrens return (0); 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens int 320ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 321fa9e4066Sahrens { 322fa9e4066Sahrens int error; 323fa9e4066Sahrens 324ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 325ecd6cf80Smarks if (error == 0) { 326ecd6cf80Smarks error = secpolicy_zfs(cr); 327db870a07Sahrens if (error) 328ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 329ecd6cf80Smarks } 330ecd6cf80Smarks return (error); 331ecd6cf80Smarks } 332ecd6cf80Smarks 333ecd6cf80Smarks static int 334ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 335ecd6cf80Smarks { 336ecd6cf80Smarks /* 337ecd6cf80Smarks * Check permissions for special properties. 338ecd6cf80Smarks */ 339ecd6cf80Smarks switch (prop) { 340ecd6cf80Smarks case ZFS_PROP_ZONED: 341ecd6cf80Smarks /* 342ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 343ecd6cf80Smarks */ 344ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 345ecd6cf80Smarks return (EPERM); 346ecd6cf80Smarks break; 347ecd6cf80Smarks 348ecd6cf80Smarks case ZFS_PROP_QUOTA: 349ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 350ecd6cf80Smarks uint64_t zoned; 351ecd6cf80Smarks char setpoint[MAXNAMELEN]; 352ecd6cf80Smarks /* 353ecd6cf80Smarks * Unprivileged users are allowed to modify the 354ecd6cf80Smarks * quota on things *under* (ie. contained by) 355ecd6cf80Smarks * the thing they own. 356ecd6cf80Smarks */ 357ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 358ecd6cf80Smarks setpoint)) 359ecd6cf80Smarks return (EPERM); 360db870a07Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 361ecd6cf80Smarks return (EPERM); 362ecd6cf80Smarks } 363db870a07Sahrens break; 364ecd6cf80Smarks } 365ecd6cf80Smarks 36691ebeef5Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 367ecd6cf80Smarks } 368ecd6cf80Smarks 369ecd6cf80Smarks int 370ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 371ecd6cf80Smarks { 372ecd6cf80Smarks int error; 373ecd6cf80Smarks 374ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 375ecd6cf80Smarks if (error) 376fa9e4066Sahrens return (error); 377fa9e4066Sahrens 378ecd6cf80Smarks /* 379ecd6cf80Smarks * permission to set permissions will be evaluated later in 380ecd6cf80Smarks * dsl_deleg_can_allow() 381ecd6cf80Smarks */ 382ecd6cf80Smarks return (0); 383ecd6cf80Smarks } 384ecd6cf80Smarks 385ecd6cf80Smarks int 386ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 387ecd6cf80Smarks { 388ecd6cf80Smarks int error; 389ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 390ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 391ecd6cf80Smarks if (error == 0) 392ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 393ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 394ecd6cf80Smarks return (error); 395ecd6cf80Smarks } 396ecd6cf80Smarks 397ecd6cf80Smarks int 398ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 399ecd6cf80Smarks { 400ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 401ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 402ecd6cf80Smarks } 403ecd6cf80Smarks 404743a77edSAlan Wright static int 405743a77edSAlan Wright zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) 406743a77edSAlan Wright { 407743a77edSAlan Wright vnode_t *vp; 408743a77edSAlan Wright int error; 409743a77edSAlan Wright 410743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 411743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 412743a77edSAlan Wright return (error); 413743a77edSAlan Wright 414743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 415743a77edSAlan Wright 416743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 417743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 418743a77edSAlan Wright zc->zc_name) != 0)) { 419743a77edSAlan Wright VN_RELE(vp); 420743a77edSAlan Wright return (EPERM); 421743a77edSAlan Wright } 422743a77edSAlan Wright 423743a77edSAlan Wright VN_RELE(vp); 424743a77edSAlan Wright return (dsl_deleg_access(zc->zc_name, 425743a77edSAlan Wright ZFS_DELEG_PERM_SHARE, cr)); 426743a77edSAlan Wright } 427743a77edSAlan Wright 428ecd6cf80Smarks int 429ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 430ecd6cf80Smarks { 431ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 432ecd6cf80Smarks return (EPERM); 433ecd6cf80Smarks 4343cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 435ecd6cf80Smarks return (0); 436ecd6cf80Smarks } else { 437743a77edSAlan Wright return (zfs_secpolicy_deleg_share(zc, cr)); 438743a77edSAlan Wright } 439743a77edSAlan Wright } 440ecd6cf80Smarks 441743a77edSAlan Wright int 442743a77edSAlan Wright zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) 443743a77edSAlan Wright { 444743a77edSAlan Wright if (!INGLOBALZONE(curproc)) 445743a77edSAlan Wright return (EPERM); 446ecd6cf80Smarks 447743a77edSAlan Wright if (secpolicy_smb(cr) == 0) { 448743a77edSAlan Wright return (0); 449743a77edSAlan Wright } else { 450743a77edSAlan Wright return (zfs_secpolicy_deleg_share(zc, cr)); 451ecd6cf80Smarks } 452fa9e4066Sahrens } 453fa9e4066Sahrens 454fa9e4066Sahrens static int 455ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 456fa9e4066Sahrens { 457fa9e4066Sahrens char *cp; 458fa9e4066Sahrens 459fa9e4066Sahrens /* 460fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 461fa9e4066Sahrens */ 462ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 463ecd6cf80Smarks cp = strrchr(parent, '@'); 464fa9e4066Sahrens if (cp != NULL) { 465fa9e4066Sahrens cp[0] = '\0'; 466fa9e4066Sahrens } else { 467ecd6cf80Smarks cp = strrchr(parent, '/'); 468fa9e4066Sahrens if (cp == NULL) 469fa9e4066Sahrens return (ENOENT); 470fa9e4066Sahrens cp[0] = '\0'; 471ecd6cf80Smarks } 472ecd6cf80Smarks 473ecd6cf80Smarks return (0); 474ecd6cf80Smarks } 475ecd6cf80Smarks 476ecd6cf80Smarks int 477ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 478ecd6cf80Smarks { 479ecd6cf80Smarks int error; 480ecd6cf80Smarks 481ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 482ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 483ecd6cf80Smarks return (error); 484ecd6cf80Smarks 485ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 486ecd6cf80Smarks } 487ecd6cf80Smarks 488ecd6cf80Smarks static int 489ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 490ecd6cf80Smarks { 491ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 492ecd6cf80Smarks } 493ecd6cf80Smarks 494ecd6cf80Smarks /* 495ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 496ecd6cf80Smarks */ 497ecd6cf80Smarks /* ARGSUSED */ 498ecd6cf80Smarks static int 499ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 500ecd6cf80Smarks { 501ecd6cf80Smarks return (secpolicy_zfs(cr)); 502ecd6cf80Smarks } 503ecd6cf80Smarks 504ecd6cf80Smarks int 505ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 506ecd6cf80Smarks { 507ecd6cf80Smarks char parentname[MAXNAMELEN]; 508ecd6cf80Smarks int error; 509ecd6cf80Smarks 510ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 511ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 512ecd6cf80Smarks return (error); 513ecd6cf80Smarks 514ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 515ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 516ecd6cf80Smarks return (error); 517ecd6cf80Smarks 518ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 519ecd6cf80Smarks sizeof (parentname))) != 0) 520ecd6cf80Smarks return (error); 521ecd6cf80Smarks 522ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 523ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 524ecd6cf80Smarks return (error); 525ecd6cf80Smarks 526ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 527ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 528ecd6cf80Smarks return (error); 529ecd6cf80Smarks 530ecd6cf80Smarks return (error); 531ecd6cf80Smarks } 532ecd6cf80Smarks 533ecd6cf80Smarks static int 534ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 535ecd6cf80Smarks { 536ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 537ecd6cf80Smarks } 538ecd6cf80Smarks 539ecd6cf80Smarks static int 540ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 541ecd6cf80Smarks { 542ecd6cf80Smarks char parentname[MAXNAMELEN]; 543ecd6cf80Smarks objset_t *clone; 544ecd6cf80Smarks int error; 545ecd6cf80Smarks 546ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 547ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 548ecd6cf80Smarks if (error) 549ecd6cf80Smarks return (error); 550ecd6cf80Smarks 551ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 552745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 553ecd6cf80Smarks 554ecd6cf80Smarks if (error == 0) { 555ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 556ecd6cf80Smarks dsl_dir_t *dd; 557ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 558ecd6cf80Smarks 559ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 560745cd3c5Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 561745cd3c5Smaybee dd->dd_phys->dd_origin_obj, FTAG, &pclone); 562ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 563ecd6cf80Smarks if (error) { 564ecd6cf80Smarks dmu_objset_close(clone); 565ecd6cf80Smarks return (error); 566ecd6cf80Smarks } 567ecd6cf80Smarks 568ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 569ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 570ecd6cf80Smarks 571ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 572ecd6cf80Smarks dmu_objset_close(clone); 573745cd3c5Smaybee dsl_dataset_rele(pclone, FTAG); 574ecd6cf80Smarks if (error == 0) 575ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 576ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 577ecd6cf80Smarks } 578ecd6cf80Smarks return (error); 579ecd6cf80Smarks } 580ecd6cf80Smarks 581ecd6cf80Smarks static int 582ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 583ecd6cf80Smarks { 584ecd6cf80Smarks int error; 585ecd6cf80Smarks 586ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 587ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 588ecd6cf80Smarks return (error); 589ecd6cf80Smarks 590ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 591ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 592ecd6cf80Smarks return (error); 593ecd6cf80Smarks 594ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 595ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 596ecd6cf80Smarks } 597ecd6cf80Smarks 598ecd6cf80Smarks int 599ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 600ecd6cf80Smarks { 601ecd6cf80Smarks int error; 602ecd6cf80Smarks 603ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 604ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 605ecd6cf80Smarks return (error); 606ecd6cf80Smarks 607ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 608ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 609ecd6cf80Smarks 610ecd6cf80Smarks return (error); 611ecd6cf80Smarks } 612ecd6cf80Smarks 613ecd6cf80Smarks static int 614ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 615ecd6cf80Smarks { 616ecd6cf80Smarks 617ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 618ecd6cf80Smarks } 619ecd6cf80Smarks 620ecd6cf80Smarks static int 621ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 622ecd6cf80Smarks { 623ecd6cf80Smarks char parentname[MAXNAMELEN]; 624ecd6cf80Smarks int error; 625ecd6cf80Smarks 626ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 627ecd6cf80Smarks sizeof (parentname))) != 0) 628ecd6cf80Smarks return (error); 629fa9e4066Sahrens 630ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 631ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 632ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 633ecd6cf80Smarks return (error); 634fa9e4066Sahrens } 635fa9e4066Sahrens 636ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 637ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 638ecd6cf80Smarks return (error); 639ecd6cf80Smarks 640ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 641ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 642ecd6cf80Smarks 643ecd6cf80Smarks return (error); 644ecd6cf80Smarks } 645ecd6cf80Smarks 646ecd6cf80Smarks static int 647ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 648ecd6cf80Smarks { 649ecd6cf80Smarks int error; 650ecd6cf80Smarks 651ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 652ecd6cf80Smarks if (error) { 653ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 654ecd6cf80Smarks } 655ecd6cf80Smarks return (error); 656fa9e4066Sahrens } 657fa9e4066Sahrens 658fa9e4066Sahrens /* 659fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 660fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 661fa9e4066Sahrens */ 662fa9e4066Sahrens /* ARGSUSED */ 663fa9e4066Sahrens static int 664ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 665fa9e4066Sahrens { 666fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 667fa9e4066Sahrens return (EPERM); 668fa9e4066Sahrens 669fa9e4066Sahrens return (0); 670fa9e4066Sahrens } 671fa9e4066Sahrens 672ecd6cf80Smarks /* 673ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 674ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 675ecd6cf80Smarks * the minor nodes. 676ecd6cf80Smarks */ 677ecd6cf80Smarks static int 678ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 679ecd6cf80Smarks { 680ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 681ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 682ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 683ecd6cf80Smarks } 684ecd6cf80Smarks 685ecd6cf80Smarks return (0); 686ecd6cf80Smarks } 687ecd6cf80Smarks 688ea8dc4b6Seschrock /* 689ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 690ea8dc4b6Seschrock */ 691ea8dc4b6Seschrock /* ARGSUSED */ 692ea8dc4b6Seschrock static int 693ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 694ea8dc4b6Seschrock { 695ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 696ea8dc4b6Seschrock } 697ea8dc4b6Seschrock 698e45ce728Sahrens static int 699e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 700e45ce728Sahrens { 701e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 702e45ce728Sahrens 703990b4856Slling if (prop == ZPROP_INVAL) { 704e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 705e45ce728Sahrens return (EINVAL); 706e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 707e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 708e45ce728Sahrens } else { 709e45ce728Sahrens if (!zfs_prop_inheritable(prop)) 710e45ce728Sahrens return (EINVAL); 711e45ce728Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 712e45ce728Sahrens } 713e45ce728Sahrens } 714e45ce728Sahrens 715*14843421SMatthew Ahrens static int 716*14843421SMatthew Ahrens zfs_secpolicy_userspace_one(zfs_cmd_t *zc, cred_t *cr) 717*14843421SMatthew Ahrens { 718*14843421SMatthew Ahrens int err = zfs_secpolicy_read(zc, cr); 719*14843421SMatthew Ahrens if (err) 720*14843421SMatthew Ahrens return (err); 721*14843421SMatthew Ahrens 722*14843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 723*14843421SMatthew Ahrens return (EINVAL); 724*14843421SMatthew Ahrens 725*14843421SMatthew Ahrens if (zc->zc_value[0] == 0) { 726*14843421SMatthew Ahrens /* 727*14843421SMatthew Ahrens * They are asking about a posix uid/gid. If it's 728*14843421SMatthew Ahrens * themself, allow it. 729*14843421SMatthew Ahrens */ 730*14843421SMatthew Ahrens if (zc->zc_objset_type == ZFS_PROP_USERUSED || 731*14843421SMatthew Ahrens zc->zc_objset_type == ZFS_PROP_USERQUOTA) { 732*14843421SMatthew Ahrens if (zc->zc_guid == crgetuid(cr)) 733*14843421SMatthew Ahrens return (0); 734*14843421SMatthew Ahrens } else { 735*14843421SMatthew Ahrens if (groupmember(zc->zc_guid, cr)) 736*14843421SMatthew Ahrens return (0); 737*14843421SMatthew Ahrens } 738*14843421SMatthew Ahrens } 739*14843421SMatthew Ahrens 740*14843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 741*14843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 742*14843421SMatthew Ahrens } 743*14843421SMatthew Ahrens 744*14843421SMatthew Ahrens static int 745*14843421SMatthew Ahrens zfs_secpolicy_userspace_many(zfs_cmd_t *zc, cred_t *cr) 746*14843421SMatthew Ahrens { 747*14843421SMatthew Ahrens int err = zfs_secpolicy_read(zc, cr); 748*14843421SMatthew Ahrens if (err) 749*14843421SMatthew Ahrens return (err); 750*14843421SMatthew Ahrens 751*14843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 752*14843421SMatthew Ahrens return (EINVAL); 753*14843421SMatthew Ahrens 754*14843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 755*14843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 756*14843421SMatthew Ahrens } 757*14843421SMatthew Ahrens 758*14843421SMatthew Ahrens static int 759*14843421SMatthew Ahrens zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, cred_t *cr) 760*14843421SMatthew Ahrens { 761*14843421SMatthew Ahrens return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, cr)); 762*14843421SMatthew Ahrens } 763*14843421SMatthew Ahrens 764fa9e4066Sahrens /* 765fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 766fa9e4066Sahrens */ 767fa9e4066Sahrens static int 768990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 769fa9e4066Sahrens { 770fa9e4066Sahrens char *packed; 771fa9e4066Sahrens int error; 772990b4856Slling nvlist_t *list = NULL; 773fa9e4066Sahrens 774fa9e4066Sahrens /* 775e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 776fa9e4066Sahrens */ 777990b4856Slling if (size == 0) 778fa9e4066Sahrens return (EINVAL); 779fa9e4066Sahrens 780fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 781fa9e4066Sahrens 782990b4856Slling if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 783fa9e4066Sahrens kmem_free(packed, size); 784fa9e4066Sahrens return (error); 785fa9e4066Sahrens } 786fa9e4066Sahrens 787990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 788fa9e4066Sahrens kmem_free(packed, size); 789fa9e4066Sahrens return (error); 790fa9e4066Sahrens } 791fa9e4066Sahrens 792fa9e4066Sahrens kmem_free(packed, size); 793fa9e4066Sahrens 794990b4856Slling *nvp = list; 795fa9e4066Sahrens return (0); 796fa9e4066Sahrens } 797fa9e4066Sahrens 798e9dbad6fSeschrock static int 799e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 800e9dbad6fSeschrock { 801e9dbad6fSeschrock char *packed = NULL; 802e9dbad6fSeschrock size_t size; 803e9dbad6fSeschrock int error; 804e9dbad6fSeschrock 805e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 806e9dbad6fSeschrock 807e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 808e9dbad6fSeschrock error = ENOMEM; 809e9dbad6fSeschrock } else { 810da165920Smarks packed = kmem_alloc(size, KM_SLEEP); 811e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 812e9dbad6fSeschrock KM_SLEEP) == 0); 813e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 814e9dbad6fSeschrock size); 815e9dbad6fSeschrock kmem_free(packed, size); 816e9dbad6fSeschrock } 817e9dbad6fSeschrock 818e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 819e9dbad6fSeschrock return (error); 820e9dbad6fSeschrock } 821e9dbad6fSeschrock 822*14843421SMatthew Ahrens static int 823*14843421SMatthew Ahrens getzfsvfs(const char *dsname, zfsvfs_t **zvp) 824*14843421SMatthew Ahrens { 825*14843421SMatthew Ahrens objset_t *os; 826*14843421SMatthew Ahrens int error; 827*14843421SMatthew Ahrens 828*14843421SMatthew Ahrens error = dmu_objset_open(dsname, DMU_OST_ZFS, 829*14843421SMatthew Ahrens DS_MODE_USER | DS_MODE_READONLY, &os); 830*14843421SMatthew Ahrens if (error) 831*14843421SMatthew Ahrens return (error); 832*14843421SMatthew Ahrens 833*14843421SMatthew Ahrens mutex_enter(&os->os->os_user_ptr_lock); 834*14843421SMatthew Ahrens *zvp = dmu_objset_get_user(os); 835*14843421SMatthew Ahrens if (*zvp) { 836*14843421SMatthew Ahrens VFS_HOLD((*zvp)->z_vfs); 837*14843421SMatthew Ahrens } else { 838*14843421SMatthew Ahrens error = ESRCH; 839*14843421SMatthew Ahrens } 840*14843421SMatthew Ahrens mutex_exit(&os->os->os_user_ptr_lock); 841*14843421SMatthew Ahrens dmu_objset_close(os); 842*14843421SMatthew Ahrens return (error); 843*14843421SMatthew Ahrens } 844*14843421SMatthew Ahrens 845*14843421SMatthew Ahrens /* 846*14843421SMatthew Ahrens * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 847*14843421SMatthew Ahrens * case its z_vfs will be NULL, and it will be opened as the owner. 848*14843421SMatthew Ahrens */ 849*14843421SMatthew Ahrens static int 850*14843421SMatthew Ahrens zfsvfs_hold(const char *name, boolean_t readonly, void *tag, zfsvfs_t **zvp) 851*14843421SMatthew Ahrens { 852*14843421SMatthew Ahrens int error = 0; 853*14843421SMatthew Ahrens int mode = DS_MODE_OWNER | (readonly ? DS_MODE_READONLY : 0); 854*14843421SMatthew Ahrens 855*14843421SMatthew Ahrens if (getzfsvfs(name, zvp) != 0) 856*14843421SMatthew Ahrens error = zfsvfs_create(name, mode, zvp); 857*14843421SMatthew Ahrens if (error == 0) { 858*14843421SMatthew Ahrens rrw_enter(&(*zvp)->z_teardown_lock, RW_READER, tag); 859*14843421SMatthew Ahrens if ((*zvp)->z_unmounted) { 860*14843421SMatthew Ahrens /* 861*14843421SMatthew Ahrens * XXX we could probably try again, since the unmounting 862*14843421SMatthew Ahrens * thread should be just about to disassociate the 863*14843421SMatthew Ahrens * objset from the zfsvfs. 864*14843421SMatthew Ahrens */ 865*14843421SMatthew Ahrens rrw_exit(&(*zvp)->z_teardown_lock, tag); 866*14843421SMatthew Ahrens return (EBUSY); 867*14843421SMatthew Ahrens } 868*14843421SMatthew Ahrens } 869*14843421SMatthew Ahrens return (error); 870*14843421SMatthew Ahrens } 871*14843421SMatthew Ahrens 872*14843421SMatthew Ahrens static void 873*14843421SMatthew Ahrens zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 874*14843421SMatthew Ahrens { 875*14843421SMatthew Ahrens rrw_exit(&zfsvfs->z_teardown_lock, tag); 876*14843421SMatthew Ahrens 877*14843421SMatthew Ahrens if (zfsvfs->z_vfs) { 878*14843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 879*14843421SMatthew Ahrens } else { 880*14843421SMatthew Ahrens dmu_objset_close(zfsvfs->z_os); 881*14843421SMatthew Ahrens zfsvfs_free(zfsvfs); 882*14843421SMatthew Ahrens } 883*14843421SMatthew Ahrens } 884*14843421SMatthew Ahrens 885fa9e4066Sahrens static int 886fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 887fa9e4066Sahrens { 888fa9e4066Sahrens int error; 889990b4856Slling nvlist_t *config, *props = NULL; 8900a48a24eStimh nvlist_t *rootprops = NULL; 8910a48a24eStimh nvlist_t *zplprops = NULL; 892228975ccSek char *buf; 893fa9e4066Sahrens 894990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 895990b4856Slling &config)) 896fa9e4066Sahrens return (error); 8972a6b87f0Sek 898990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 899990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 900990b4856Slling nvlist_free(config); 901990b4856Slling return (error); 902990b4856Slling } 903990b4856Slling 9040a48a24eStimh if (props) { 9050a48a24eStimh nvlist_t *nvl = NULL; 9060a48a24eStimh uint64_t version = SPA_VERSION; 9070a48a24eStimh 9080a48a24eStimh (void) nvlist_lookup_uint64(props, 9090a48a24eStimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 9100a48a24eStimh if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 9110a48a24eStimh error = EINVAL; 9120a48a24eStimh goto pool_props_bad; 9130a48a24eStimh } 9140a48a24eStimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 9150a48a24eStimh if (nvl) { 9160a48a24eStimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 9170a48a24eStimh if (error != 0) { 9180a48a24eStimh nvlist_free(config); 9190a48a24eStimh nvlist_free(props); 9200a48a24eStimh return (error); 9210a48a24eStimh } 9220a48a24eStimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 9230a48a24eStimh } 9240a48a24eStimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 9250a48a24eStimh error = zfs_fill_zplprops_root(version, rootprops, 9260a48a24eStimh zplprops, NULL); 9270a48a24eStimh if (error) 9280a48a24eStimh goto pool_props_bad; 9290a48a24eStimh } 9300a48a24eStimh 9312a6b87f0Sek buf = history_str_get(zc); 932fa9e4066Sahrens 9330a48a24eStimh error = spa_create(zc->zc_name, config, props, buf, zplprops); 9340a48a24eStimh 9350a48a24eStimh /* 9360a48a24eStimh * Set the remaining root properties 9370a48a24eStimh */ 9380a48a24eStimh if (!error && 9390a48a24eStimh (error = zfs_set_prop_nvlist(zc->zc_name, rootprops)) != 0) 9400a48a24eStimh (void) spa_destroy(zc->zc_name); 941fa9e4066Sahrens 9422a6b87f0Sek if (buf != NULL) 9432a6b87f0Sek history_str_free(buf); 944990b4856Slling 9450a48a24eStimh pool_props_bad: 9460a48a24eStimh nvlist_free(rootprops); 9470a48a24eStimh nvlist_free(zplprops); 948fa9e4066Sahrens nvlist_free(config); 9490a48a24eStimh nvlist_free(props); 950990b4856Slling 951fa9e4066Sahrens return (error); 952fa9e4066Sahrens } 953fa9e4066Sahrens 954fa9e4066Sahrens static int 955fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 956fa9e4066Sahrens { 957ecd6cf80Smarks int error; 958ecd6cf80Smarks zfs_log_history(zc); 959ecd6cf80Smarks error = spa_destroy(zc->zc_name); 960ecd6cf80Smarks return (error); 961fa9e4066Sahrens } 962fa9e4066Sahrens 963fa9e4066Sahrens static int 964fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 965fa9e4066Sahrens { 966fa9e4066Sahrens int error; 967990b4856Slling nvlist_t *config, *props = NULL; 968fa9e4066Sahrens uint64_t guid; 969fa9e4066Sahrens 970990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 971990b4856Slling &config)) != 0) 972990b4856Slling return (error); 973990b4856Slling 974990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 975990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 976990b4856Slling nvlist_free(config); 977fa9e4066Sahrens return (error); 978990b4856Slling } 979fa9e4066Sahrens 980fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 981ea8dc4b6Seschrock guid != zc->zc_guid) 982fa9e4066Sahrens error = EINVAL; 983c5904d13Seschrock else if (zc->zc_cookie) 984c5904d13Seschrock error = spa_import_faulted(zc->zc_name, config, 985c5904d13Seschrock props); 986fa9e4066Sahrens else 987990b4856Slling error = spa_import(zc->zc_name, config, props); 988fa9e4066Sahrens 989fa9e4066Sahrens nvlist_free(config); 990fa9e4066Sahrens 991990b4856Slling if (props) 992990b4856Slling nvlist_free(props); 993990b4856Slling 994fa9e4066Sahrens return (error); 995fa9e4066Sahrens } 996fa9e4066Sahrens 997fa9e4066Sahrens static int 998fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 999fa9e4066Sahrens { 1000ecd6cf80Smarks int error; 100189a89ebfSlling boolean_t force = (boolean_t)zc->zc_cookie; 1002394ab0cbSGeorge Wilson boolean_t hardforce = (boolean_t)zc->zc_guid; 100389a89ebfSlling 1004ecd6cf80Smarks zfs_log_history(zc); 1005394ab0cbSGeorge Wilson error = spa_export(zc->zc_name, NULL, force, hardforce); 1006ecd6cf80Smarks return (error); 1007fa9e4066Sahrens } 1008fa9e4066Sahrens 1009fa9e4066Sahrens static int 1010fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 1011fa9e4066Sahrens { 1012fa9e4066Sahrens nvlist_t *configs; 1013fa9e4066Sahrens int error; 1014fa9e4066Sahrens 1015fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1016fa9e4066Sahrens return (EEXIST); 1017fa9e4066Sahrens 1018e9dbad6fSeschrock error = put_nvlist(zc, configs); 1019fa9e4066Sahrens 1020fa9e4066Sahrens nvlist_free(configs); 1021fa9e4066Sahrens 1022fa9e4066Sahrens return (error); 1023fa9e4066Sahrens } 1024fa9e4066Sahrens 1025fa9e4066Sahrens static int 1026fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 1027fa9e4066Sahrens { 1028fa9e4066Sahrens nvlist_t *config; 1029fa9e4066Sahrens int error; 1030ea8dc4b6Seschrock int ret = 0; 1031fa9e4066Sahrens 1032e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 1033e9dbad6fSeschrock sizeof (zc->zc_value)); 1034fa9e4066Sahrens 1035fa9e4066Sahrens if (config != NULL) { 1036e9dbad6fSeschrock ret = put_nvlist(zc, config); 1037fa9e4066Sahrens nvlist_free(config); 1038ea8dc4b6Seschrock 1039ea8dc4b6Seschrock /* 1040ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 1041ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 1042ea8dc4b6Seschrock * in 'zc_cookie'. 1043ea8dc4b6Seschrock */ 1044ea8dc4b6Seschrock zc->zc_cookie = error; 1045fa9e4066Sahrens } else { 1046ea8dc4b6Seschrock ret = error; 1047fa9e4066Sahrens } 1048fa9e4066Sahrens 1049ea8dc4b6Seschrock return (ret); 1050fa9e4066Sahrens } 1051fa9e4066Sahrens 1052fa9e4066Sahrens /* 1053fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 1054fa9e4066Sahrens * user land knows which devices are available and overall pool health. 1055fa9e4066Sahrens */ 1056fa9e4066Sahrens static int 1057fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1058fa9e4066Sahrens { 1059fa9e4066Sahrens nvlist_t *tryconfig, *config; 1060fa9e4066Sahrens int error; 1061fa9e4066Sahrens 1062990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1063990b4856Slling &tryconfig)) != 0) 1064fa9e4066Sahrens return (error); 1065fa9e4066Sahrens 1066fa9e4066Sahrens config = spa_tryimport(tryconfig); 1067fa9e4066Sahrens 1068fa9e4066Sahrens nvlist_free(tryconfig); 1069fa9e4066Sahrens 1070fa9e4066Sahrens if (config == NULL) 1071fa9e4066Sahrens return (EINVAL); 1072fa9e4066Sahrens 1073e9dbad6fSeschrock error = put_nvlist(zc, config); 1074fa9e4066Sahrens nvlist_free(config); 1075fa9e4066Sahrens 1076fa9e4066Sahrens return (error); 1077fa9e4066Sahrens } 1078fa9e4066Sahrens 1079fa9e4066Sahrens static int 1080fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 1081fa9e4066Sahrens { 1082fa9e4066Sahrens spa_t *spa; 1083fa9e4066Sahrens int error; 1084fa9e4066Sahrens 108506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 108606eeb2adSek return (error); 108706eeb2adSek 1088088f3894Sahrens error = spa_scrub(spa, zc->zc_cookie); 108906eeb2adSek 109006eeb2adSek spa_close(spa, FTAG); 109106eeb2adSek 1092fa9e4066Sahrens return (error); 1093fa9e4066Sahrens } 1094fa9e4066Sahrens 1095fa9e4066Sahrens static int 1096fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 1097fa9e4066Sahrens { 1098fa9e4066Sahrens spa_t *spa; 1099fa9e4066Sahrens int error; 1100fa9e4066Sahrens 1101fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1102fa9e4066Sahrens if (error == 0) { 1103fa9e4066Sahrens spa_freeze(spa); 1104fa9e4066Sahrens spa_close(spa, FTAG); 1105fa9e4066Sahrens } 1106fa9e4066Sahrens return (error); 1107fa9e4066Sahrens } 1108fa9e4066Sahrens 1109eaca9bbdSeschrock static int 1110eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 1111eaca9bbdSeschrock { 1112eaca9bbdSeschrock spa_t *spa; 1113eaca9bbdSeschrock int error; 1114eaca9bbdSeschrock 111506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 111606eeb2adSek return (error); 111706eeb2adSek 1118558d2d50Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 1119558d2d50Slling spa_close(spa, FTAG); 1120558d2d50Slling return (EINVAL); 1121558d2d50Slling } 1122558d2d50Slling 1123990b4856Slling spa_upgrade(spa, zc->zc_cookie); 112406eeb2adSek spa_close(spa, FTAG); 112506eeb2adSek 112606eeb2adSek return (error); 112706eeb2adSek } 112806eeb2adSek 112906eeb2adSek static int 113006eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 113106eeb2adSek { 113206eeb2adSek spa_t *spa; 113306eeb2adSek char *hist_buf; 113406eeb2adSek uint64_t size; 113506eeb2adSek int error; 113606eeb2adSek 113706eeb2adSek if ((size = zc->zc_history_len) == 0) 113806eeb2adSek return (EINVAL); 113906eeb2adSek 114006eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 114106eeb2adSek return (error); 114206eeb2adSek 1143e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1144d7306b64Sek spa_close(spa, FTAG); 1145d7306b64Sek return (ENOTSUP); 1146d7306b64Sek } 1147d7306b64Sek 114806eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 114906eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 115006eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 1151ecd6cf80Smarks error = xcopyout(hist_buf, 1152ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 115306eeb2adSek zc->zc_history_len); 115406eeb2adSek } 115506eeb2adSek 115606eeb2adSek spa_close(spa, FTAG); 115706eeb2adSek kmem_free(hist_buf, size); 115806eeb2adSek return (error); 115906eeb2adSek } 116006eeb2adSek 116155434c77Sek static int 116255434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 116355434c77Sek { 116455434c77Sek int error; 116555434c77Sek 1166b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 116755434c77Sek return (error); 116855434c77Sek 116955434c77Sek return (0); 117055434c77Sek } 117155434c77Sek 117255434c77Sek static int 117355434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 117455434c77Sek { 117555434c77Sek objset_t *osp; 117655434c77Sek int error; 117755434c77Sek 117855434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 1179745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &osp)) != 0) 118055434c77Sek return (error); 118155434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 118255434c77Sek sizeof (zc->zc_value)); 118355434c77Sek dmu_objset_close(osp); 118455434c77Sek 118555434c77Sek return (error); 118655434c77Sek } 118755434c77Sek 1188fa9e4066Sahrens static int 1189fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1190fa9e4066Sahrens { 1191fa9e4066Sahrens spa_t *spa; 1192fa9e4066Sahrens int error; 1193e7cbe64fSgw nvlist_t *config, **l2cache, **spares; 1194e7cbe64fSgw uint_t nl2cache = 0, nspares = 0; 1195fa9e4066Sahrens 1196fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1197fa9e4066Sahrens if (error != 0) 1198fa9e4066Sahrens return (error); 1199fa9e4066Sahrens 1200fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1201fa94a07fSbrendan &config); 1202fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1203fa94a07fSbrendan &l2cache, &nl2cache); 1204fa94a07fSbrendan 1205e7cbe64fSgw (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1206e7cbe64fSgw &spares, &nspares); 1207e7cbe64fSgw 1208b1b8ab34Slling /* 1209b1b8ab34Slling * A root pool with concatenated devices is not supported. 1210e7cbe64fSgw * Thus, can not add a device to a root pool. 1211e7cbe64fSgw * 1212e7cbe64fSgw * Intent log device can not be added to a rootpool because 1213e7cbe64fSgw * during mountroot, zil is replayed, a seperated log device 1214e7cbe64fSgw * can not be accessed during the mountroot time. 1215e7cbe64fSgw * 1216e7cbe64fSgw * l2cache and spare devices are ok to be added to a rootpool. 1217b1b8ab34Slling */ 1218e7cbe64fSgw if (spa->spa_bootfs != 0 && nl2cache == 0 && nspares == 0) { 1219b1b8ab34Slling spa_close(spa, FTAG); 1220b1b8ab34Slling return (EDOM); 1221b1b8ab34Slling } 1222b1b8ab34Slling 1223fa94a07fSbrendan if (error == 0) { 1224fa9e4066Sahrens error = spa_vdev_add(spa, config); 1225fa9e4066Sahrens nvlist_free(config); 1226fa9e4066Sahrens } 1227fa9e4066Sahrens spa_close(spa, FTAG); 1228fa9e4066Sahrens return (error); 1229fa9e4066Sahrens } 1230fa9e4066Sahrens 1231fa9e4066Sahrens static int 1232fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1233fa9e4066Sahrens { 123499653d4eSeschrock spa_t *spa; 123599653d4eSeschrock int error; 123699653d4eSeschrock 123799653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 123899653d4eSeschrock if (error != 0) 123999653d4eSeschrock return (error); 124099653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 124199653d4eSeschrock spa_close(spa, FTAG); 124299653d4eSeschrock return (error); 1243fa9e4066Sahrens } 1244fa9e4066Sahrens 1245fa9e4066Sahrens static int 12463d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1247fa9e4066Sahrens { 1248fa9e4066Sahrens spa_t *spa; 1249fa9e4066Sahrens int error; 12503d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1251fa9e4066Sahrens 125206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1253fa9e4066Sahrens return (error); 12543d7072f8Seschrock switch (zc->zc_cookie) { 12553d7072f8Seschrock case VDEV_STATE_ONLINE: 12563d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 12573d7072f8Seschrock break; 1258fa9e4066Sahrens 12593d7072f8Seschrock case VDEV_STATE_OFFLINE: 12603d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 12613d7072f8Seschrock break; 1262fa9e4066Sahrens 12633d7072f8Seschrock case VDEV_STATE_FAULTED: 12643d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 12653d7072f8Seschrock break; 12663d7072f8Seschrock 12673d7072f8Seschrock case VDEV_STATE_DEGRADED: 12683d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 12693d7072f8Seschrock break; 12703d7072f8Seschrock 12713d7072f8Seschrock default: 12723d7072f8Seschrock error = EINVAL; 12733d7072f8Seschrock } 12743d7072f8Seschrock zc->zc_cookie = newstate; 1275fa9e4066Sahrens spa_close(spa, FTAG); 1276fa9e4066Sahrens return (error); 1277fa9e4066Sahrens } 1278fa9e4066Sahrens 1279fa9e4066Sahrens static int 1280fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1281fa9e4066Sahrens { 1282fa9e4066Sahrens spa_t *spa; 1283fa9e4066Sahrens int replacing = zc->zc_cookie; 1284fa9e4066Sahrens nvlist_t *config; 1285fa9e4066Sahrens int error; 1286fa9e4066Sahrens 128706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1288fa9e4066Sahrens return (error); 1289fa9e4066Sahrens 1290990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1291990b4856Slling &config)) == 0) { 1292ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1293fa9e4066Sahrens nvlist_free(config); 1294fa9e4066Sahrens } 1295fa9e4066Sahrens 1296fa9e4066Sahrens spa_close(spa, FTAG); 1297fa9e4066Sahrens return (error); 1298fa9e4066Sahrens } 1299fa9e4066Sahrens 1300fa9e4066Sahrens static int 1301fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1302fa9e4066Sahrens { 1303fa9e4066Sahrens spa_t *spa; 1304fa9e4066Sahrens int error; 1305fa9e4066Sahrens 130606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1307fa9e4066Sahrens return (error); 1308fa9e4066Sahrens 13098ad4d6ddSJeff Bonwick error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 1310fa9e4066Sahrens 1311fa9e4066Sahrens spa_close(spa, FTAG); 1312fa9e4066Sahrens return (error); 1313fa9e4066Sahrens } 1314fa9e4066Sahrens 1315c67d9675Seschrock static int 1316c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1317c67d9675Seschrock { 1318c67d9675Seschrock spa_t *spa; 1319e9dbad6fSeschrock char *path = zc->zc_value; 1320ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1321c67d9675Seschrock int error; 1322c67d9675Seschrock 1323c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1324c67d9675Seschrock if (error != 0) 1325c67d9675Seschrock return (error); 1326c67d9675Seschrock 1327c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1328c67d9675Seschrock spa_close(spa, FTAG); 1329c67d9675Seschrock return (error); 1330c67d9675Seschrock } 1331c67d9675Seschrock 13323cb34c60Sahrens /* 13333cb34c60Sahrens * inputs: 13343cb34c60Sahrens * zc_name name of filesystem 13353cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13363cb34c60Sahrens * 13373cb34c60Sahrens * outputs: 13383cb34c60Sahrens * zc_objset_stats stats 13393cb34c60Sahrens * zc_nvlist_dst property nvlist 13403cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 13413cb34c60Sahrens */ 1342fa9e4066Sahrens static int 1343fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1344fa9e4066Sahrens { 1345fa9e4066Sahrens objset_t *os = NULL; 1346fa9e4066Sahrens int error; 13477f7322feSeschrock nvlist_t *nv; 1348fa9e4066Sahrens 1349745cd3c5Smaybee if (error = dmu_objset_open(zc->zc_name, 1350745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1351fa9e4066Sahrens return (error); 1352fa9e4066Sahrens 1353a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1354fa9e4066Sahrens 13555ad82045Snd if (zc->zc_nvlist_dst != 0 && 1356745cd3c5Smaybee (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 1357a2eea2e1Sahrens dmu_objset_stats(os, nv); 1358432f72fdSahrens /* 1359bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 1360432f72fdSahrens * which we aren't supposed to do with a 1361745cd3c5Smaybee * DS_MODE_USER hold, because it could be 1362432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1363432f72fdSahrens */ 1364e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1365e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1366e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1367e7437265Sahrens } 1368e9dbad6fSeschrock error = put_nvlist(zc, nv); 13697f7322feSeschrock nvlist_free(nv); 13707f7322feSeschrock } 1371fa9e4066Sahrens 1372fa9e4066Sahrens dmu_objset_close(os); 1373fa9e4066Sahrens return (error); 1374fa9e4066Sahrens } 1375fa9e4066Sahrens 1376de8267e0Stimh static int 1377de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1378de8267e0Stimh { 1379de8267e0Stimh uint64_t value; 1380de8267e0Stimh int error; 1381de8267e0Stimh 1382de8267e0Stimh /* 1383de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 1384de8267e0Stimh * the default value (if there is one). 1385de8267e0Stimh */ 1386de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1387de8267e0Stimh return (error); 1388de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1389de8267e0Stimh return (0); 1390de8267e0Stimh } 1391de8267e0Stimh 13923cb34c60Sahrens /* 13933cb34c60Sahrens * inputs: 13943cb34c60Sahrens * zc_name name of filesystem 1395de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 13963cb34c60Sahrens * 13973cb34c60Sahrens * outputs: 1398de8267e0Stimh * zc_nvlist_dst zpl property nvlist 1399de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 14003cb34c60Sahrens */ 1401bd00f61bSrm static int 1402de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1403bd00f61bSrm { 1404de8267e0Stimh objset_t *os; 1405de8267e0Stimh int err; 1406bd00f61bSrm 1407745cd3c5Smaybee if (err = dmu_objset_open(zc->zc_name, 1408745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1409de8267e0Stimh return (err); 1410bd00f61bSrm 1411bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1412bd00f61bSrm 1413bd00f61bSrm /* 1414de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 1415745cd3c5Smaybee * which we aren't supposed to do with a DS_MODE_USER 1416745cd3c5Smaybee * hold, because it could be inconsistent. 1417bd00f61bSrm */ 1418de8267e0Stimh if (zc->zc_nvlist_dst != NULL && 1419de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 1420de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 1421de8267e0Stimh nvlist_t *nv; 1422de8267e0Stimh 1423de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1424de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1425de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1426de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1427de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1428de8267e0Stimh err = put_nvlist(zc, nv); 1429de8267e0Stimh nvlist_free(nv); 1430de8267e0Stimh } else { 1431de8267e0Stimh err = ENOENT; 1432de8267e0Stimh } 1433bd00f61bSrm dmu_objset_close(os); 1434de8267e0Stimh return (err); 1435bd00f61bSrm } 1436bd00f61bSrm 1437*14843421SMatthew Ahrens static boolean_t 1438*14843421SMatthew Ahrens dataset_name_hidden(const char *name) 1439*14843421SMatthew Ahrens { 1440*14843421SMatthew Ahrens /* 1441*14843421SMatthew Ahrens * Skip over datasets that are not visible in this zone, 1442*14843421SMatthew Ahrens * internal datasets (which have a $ in their name), and 1443*14843421SMatthew Ahrens * temporary datasets (which have a % in their name). 1444*14843421SMatthew Ahrens */ 1445*14843421SMatthew Ahrens if (strchr(name, '$') != NULL) 1446*14843421SMatthew Ahrens return (B_TRUE); 1447*14843421SMatthew Ahrens if (strchr(name, '%') != NULL) 1448*14843421SMatthew Ahrens return (B_TRUE); 1449*14843421SMatthew Ahrens if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL)) 1450*14843421SMatthew Ahrens return (B_TRUE); 1451*14843421SMatthew Ahrens return (B_FALSE); 1452*14843421SMatthew Ahrens } 1453*14843421SMatthew Ahrens 1454de8267e0Stimh /* 1455de8267e0Stimh * inputs: 1456de8267e0Stimh * zc_name name of filesystem 1457de8267e0Stimh * zc_cookie zap cursor 1458de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 1459de8267e0Stimh * 1460de8267e0Stimh * outputs: 1461de8267e0Stimh * zc_name name of next filesystem 1462*14843421SMatthew Ahrens * zc_cookie zap cursor 1463de8267e0Stimh * zc_objset_stats stats 1464de8267e0Stimh * zc_nvlist_dst property nvlist 1465de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 1466de8267e0Stimh */ 1467fa9e4066Sahrens static int 1468fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1469fa9e4066Sahrens { 147087e5029aSahrens objset_t *os; 1471fa9e4066Sahrens int error; 1472fa9e4066Sahrens char *p; 1473fa9e4066Sahrens 1474745cd3c5Smaybee if (error = dmu_objset_open(zc->zc_name, 1475745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) { 147687e5029aSahrens if (error == ENOENT) 147787e5029aSahrens error = ESRCH; 147887e5029aSahrens return (error); 1479fa9e4066Sahrens } 1480fa9e4066Sahrens 1481fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1482fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1483fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1484fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1485fa9e4066Sahrens 14865c0b6a79SRich Morris /* 14875c0b6a79SRich Morris * Pre-fetch the datasets. dmu_objset_prefetch() always returns 0 14885c0b6a79SRich Morris * but is not declared void because its called by dmu_objset_find(). 14895c0b6a79SRich Morris */ 14907f73c863SRich Morris if (zc->zc_cookie == 0) { 14917f73c863SRich Morris uint64_t cookie = 0; 14927f73c863SRich Morris int len = sizeof (zc->zc_name) - (p - zc->zc_name); 14937f73c863SRich Morris 14947f73c863SRich Morris while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) 14955c0b6a79SRich Morris (void) dmu_objset_prefetch(p, NULL); 14967f73c863SRich Morris } 14977f73c863SRich Morris 1498fa9e4066Sahrens do { 149987e5029aSahrens error = dmu_dir_list_next(os, 150087e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 150187e5029aSahrens NULL, &zc->zc_cookie); 1502fa9e4066Sahrens if (error == ENOENT) 1503fa9e4066Sahrens error = ESRCH; 1504*14843421SMatthew Ahrens } while (error == 0 && dataset_name_hidden(zc->zc_name)); 1505745cd3c5Smaybee dmu_objset_close(os); 1506fa9e4066Sahrens 1507*14843421SMatthew Ahrens if (error == 0) 150887e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1509fa9e4066Sahrens 1510fa9e4066Sahrens return (error); 1511fa9e4066Sahrens } 1512fa9e4066Sahrens 15133cb34c60Sahrens /* 15143cb34c60Sahrens * inputs: 15153cb34c60Sahrens * zc_name name of filesystem 15163cb34c60Sahrens * zc_cookie zap cursor 15173cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 15183cb34c60Sahrens * 15193cb34c60Sahrens * outputs: 15203cb34c60Sahrens * zc_name name of next snapshot 15213cb34c60Sahrens * zc_objset_stats stats 15223cb34c60Sahrens * zc_nvlist_dst property nvlist 15233cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 15243cb34c60Sahrens */ 1525fa9e4066Sahrens static int 1526fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1527fa9e4066Sahrens { 152887e5029aSahrens objset_t *os; 1529fa9e4066Sahrens int error; 1530fa9e4066Sahrens 1531745cd3c5Smaybee error = dmu_objset_open(zc->zc_name, 1532745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os); 1533745cd3c5Smaybee if (error) 1534745cd3c5Smaybee return (error == ENOENT ? ESRCH : error); 1535fa9e4066Sahrens 1536*14843421SMatthew Ahrens if (zc->zc_cookie == 0) { 15375c0b6a79SRich Morris (void) dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 15387f73c863SRich Morris NULL, DS_FIND_SNAPSHOTS); 1539*14843421SMatthew Ahrens } 1540b81d61a6Slling /* 1541b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1542b81d61a6Slling * so exit immediately. 1543b81d61a6Slling */ 1544b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 154587e5029aSahrens dmu_objset_close(os); 1546b81d61a6Slling return (ESRCH); 1547fa9e4066Sahrens } 1548fa9e4066Sahrens 154987e5029aSahrens error = dmu_snapshot_list_next(os, 155087e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 1551b38f0970Sck zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 1552745cd3c5Smaybee dmu_objset_close(os); 155387e5029aSahrens if (error == 0) 155487e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1555745cd3c5Smaybee else if (error == ENOENT) 1556745cd3c5Smaybee error = ESRCH; 1557fa9e4066Sahrens 15583cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 1559745cd3c5Smaybee if (error) 15603cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 1561fa9e4066Sahrens return (error); 1562fa9e4066Sahrens } 1563fa9e4066Sahrens 1564e7cbe64fSgw int 156591ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1566fa9e4066Sahrens { 1567e9dbad6fSeschrock nvpair_t *elem; 15685f389de5SRich Morris int error = 0; 1569e9dbad6fSeschrock uint64_t intval; 1570e9dbad6fSeschrock char *strval; 15715c0b6a79SRich Morris nvlist_t *genericnvl; 1572*14843421SMatthew Ahrens boolean_t issnap = (strchr(name, '@') != NULL); 1573e9dbad6fSeschrock 1574ecd6cf80Smarks /* 1575ecd6cf80Smarks * First validate permission to set all of the properties 1576ecd6cf80Smarks */ 1577e9dbad6fSeschrock elem = NULL; 1578e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1579db870a07Sahrens const char *propname = nvpair_name(elem); 1580db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1581e9dbad6fSeschrock 1582990b4856Slling if (prop == ZPROP_INVAL) { 1583e9dbad6fSeschrock /* 1584e9dbad6fSeschrock * If this is a user-defined property, it must be a 1585e9dbad6fSeschrock * string, and there is no further validation to do. 1586e9dbad6fSeschrock */ 1587*14843421SMatthew Ahrens if (zfs_prop_user(propname) && 1588*14843421SMatthew Ahrens nvpair_type(elem) == DATA_TYPE_STRING) { 1589*14843421SMatthew Ahrens if (error = zfs_secpolicy_write_perms(name, 1590*14843421SMatthew Ahrens ZFS_DELEG_PERM_USERPROP, CRED())) 1591*14843421SMatthew Ahrens return (error); 1592*14843421SMatthew Ahrens continue; 1593*14843421SMatthew Ahrens } 1594e9dbad6fSeschrock 1595*14843421SMatthew Ahrens if (!issnap && zfs_prop_userquota(propname) && 1596*14843421SMatthew Ahrens nvpair_type(elem) == DATA_TYPE_UINT64_ARRAY) { 1597*14843421SMatthew Ahrens const char *perm; 1598*14843421SMatthew Ahrens const char *up = zfs_userquota_prop_prefixes 1599*14843421SMatthew Ahrens [ZFS_PROP_USERQUOTA]; 1600*14843421SMatthew Ahrens if (strncmp(propname, up, strlen(up)) == 0) 1601*14843421SMatthew Ahrens perm = ZFS_DELEG_PERM_USERQUOTA; 1602*14843421SMatthew Ahrens else 1603*14843421SMatthew Ahrens perm = ZFS_DELEG_PERM_GROUPQUOTA; 1604*14843421SMatthew Ahrens if (error = zfs_secpolicy_write_perms(name, 1605*14843421SMatthew Ahrens perm, CRED())) 1606*14843421SMatthew Ahrens return (error); 1607*14843421SMatthew Ahrens continue; 1608*14843421SMatthew Ahrens } 1609*14843421SMatthew Ahrens 1610*14843421SMatthew Ahrens return (EINVAL); 1611e9dbad6fSeschrock } 1612fa9e4066Sahrens 1613*14843421SMatthew Ahrens if (issnap) 1614*14843421SMatthew Ahrens return (EINVAL); 1615*14843421SMatthew Ahrens 161691ebeef5Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1617db870a07Sahrens return (error); 1618db870a07Sahrens 1619e9dbad6fSeschrock /* 1620db870a07Sahrens * Check that this value is valid for this pool version 1621e9dbad6fSeschrock */ 1622e9dbad6fSeschrock switch (prop) { 1623c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1624c9431fa1Sahl /* 1625c9431fa1Sahl * If the user specified gzip compression, make sure 1626c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1627c9431fa1Sahl * we'll catch them later. 1628c9431fa1Sahl */ 1629c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 163015e6edf1Sgw nvpair_value_uint64(elem, &intval) == 0) { 163115e6edf1Sgw if (intval >= ZIO_COMPRESS_GZIP_1 && 163215e6edf1Sgw intval <= ZIO_COMPRESS_GZIP_9 && 16330a48a24eStimh zfs_earlier_version(name, 1634da6c28aaSamw SPA_VERSION_GZIP_COMPRESSION)) 1635da6c28aaSamw return (ENOTSUP); 163615e6edf1Sgw 163715e6edf1Sgw /* 163815e6edf1Sgw * If this is a bootable dataset then 163915e6edf1Sgw * verify that the compression algorithm 164015e6edf1Sgw * is supported for booting. We must return 164115e6edf1Sgw * something other than ENOTSUP since it 164215e6edf1Sgw * implies a downrev pool version. 164315e6edf1Sgw */ 164415e6edf1Sgw if (zfs_is_bootfs(name) && 164515e6edf1Sgw !BOOTFS_COMPRESS_VALID(intval)) 164615e6edf1Sgw return (ERANGE); 1647c9431fa1Sahl } 1648c9431fa1Sahl break; 164940feaa91Sahrens 165040feaa91Sahrens case ZFS_PROP_COPIES: 1651*14843421SMatthew Ahrens if (zfs_earlier_version(name, SPA_VERSION_DITTO_BLOCKS)) 1652da6c28aaSamw return (ENOTSUP); 165340feaa91Sahrens break; 16549e6eda55Smarks 16559e6eda55Smarks case ZFS_PROP_SHARESMB: 1656745cd3c5Smaybee if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 16579e6eda55Smarks return (ENOTSUP); 16589e6eda55Smarks break; 1659d0f3f37eSMark Shellenbaum 1660d0f3f37eSMark Shellenbaum case ZFS_PROP_ACLINHERIT: 1661d0f3f37eSMark Shellenbaum if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1662d0f3f37eSMark Shellenbaum nvpair_value_uint64(elem, &intval) == 0) 1663d0f3f37eSMark Shellenbaum if (intval == ZFS_ACL_PASSTHROUGH_X && 1664d0f3f37eSMark Shellenbaum zfs_earlier_version(name, 1665d0f3f37eSMark Shellenbaum SPA_VERSION_PASSTHROUGH_X)) 1666d0f3f37eSMark Shellenbaum return (ENOTSUP); 166740feaa91Sahrens } 1668ecd6cf80Smarks } 1669ecd6cf80Smarks 16705c0b6a79SRich Morris VERIFY(nvlist_alloc(&genericnvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1671ecd6cf80Smarks elem = NULL; 1672ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1673db870a07Sahrens const char *propname = nvpair_name(elem); 1674db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1675ecd6cf80Smarks 1676990b4856Slling if (prop == ZPROP_INVAL) { 1677*14843421SMatthew Ahrens if (zfs_prop_userquota(propname)) { 1678*14843421SMatthew Ahrens uint64_t *valary; 1679*14843421SMatthew Ahrens unsigned int vallen; 1680*14843421SMatthew Ahrens const char *domain; 1681*14843421SMatthew Ahrens zfs_userquota_prop_t type; 1682*14843421SMatthew Ahrens uint64_t rid; 1683*14843421SMatthew Ahrens uint64_t quota; 1684*14843421SMatthew Ahrens zfsvfs_t *zfsvfs; 1685*14843421SMatthew Ahrens 1686*14843421SMatthew Ahrens VERIFY(nvpair_value_uint64_array(elem, 1687*14843421SMatthew Ahrens &valary, &vallen) == 0); 1688*14843421SMatthew Ahrens VERIFY(vallen == 3); 1689*14843421SMatthew Ahrens type = valary[0]; 1690*14843421SMatthew Ahrens rid = valary[1]; 1691*14843421SMatthew Ahrens quota = valary[2]; 1692*14843421SMatthew Ahrens domain = propname + 1693*14843421SMatthew Ahrens strlen(zfs_userquota_prop_prefixes[type]); 1694*14843421SMatthew Ahrens 1695*14843421SMatthew Ahrens error = zfsvfs_hold(name, B_FALSE, FTAG, 1696*14843421SMatthew Ahrens &zfsvfs); 1697*14843421SMatthew Ahrens if (error == 0) { 1698*14843421SMatthew Ahrens error = zfs_set_userquota(zfsvfs, 1699*14843421SMatthew Ahrens type, domain, rid, quota); 1700*14843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 1701*14843421SMatthew Ahrens } 1702*14843421SMatthew Ahrens if (error == 0) 1703*14843421SMatthew Ahrens continue; 1704*14843421SMatthew Ahrens else 1705*14843421SMatthew Ahrens goto out; 1706*14843421SMatthew Ahrens } else if (zfs_prop_user(propname)) { 1707*14843421SMatthew Ahrens VERIFY(nvpair_value_string(elem, &strval) == 0); 1708*14843421SMatthew Ahrens error = dsl_prop_set(name, propname, 1, 1709*14843421SMatthew Ahrens strlen(strval) + 1, strval); 1710*14843421SMatthew Ahrens if (error == 0) 1711*14843421SMatthew Ahrens continue; 1712*14843421SMatthew Ahrens else 1713*14843421SMatthew Ahrens goto out; 1714*14843421SMatthew Ahrens } 1715ecd6cf80Smarks } 1716e9dbad6fSeschrock 1717e9dbad6fSeschrock switch (prop) { 1718e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1719e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1720e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 17215c0b6a79SRich Morris goto out; 1722e9dbad6fSeschrock break; 1723e9dbad6fSeschrock 1724a9799022Sck case ZFS_PROP_REFQUOTA: 1725a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1726a9799022Sck (error = dsl_dataset_set_quota(name, intval)) != 0) 17275c0b6a79SRich Morris goto out; 1728a9799022Sck break; 1729a9799022Sck 1730e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1731e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1732e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1733e9dbad6fSeschrock intval)) != 0) 17345c0b6a79SRich Morris goto out; 1735e9dbad6fSeschrock break; 1736e9dbad6fSeschrock 1737a9799022Sck case ZFS_PROP_REFRESERVATION: 1738a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1739a9799022Sck (error = dsl_dataset_set_reservation(name, 1740a9799022Sck intval)) != 0) 17415c0b6a79SRich Morris goto out; 1742a9799022Sck break; 1743a9799022Sck 1744e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1745e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 174691ebeef5Sahrens (error = zvol_set_volsize(name, 174791ebeef5Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 17485c0b6a79SRich Morris goto out; 1749e9dbad6fSeschrock break; 1750e9dbad6fSeschrock 1751e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1752e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1753e7437265Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 17545c0b6a79SRich Morris goto out; 1755e7437265Sahrens break; 1756e7437265Sahrens 1757e7437265Sahrens case ZFS_PROP_VERSION: 1758*14843421SMatthew Ahrens { 1759*14843421SMatthew Ahrens zfsvfs_t *zfsvfs; 1760*14843421SMatthew Ahrens 1761*14843421SMatthew Ahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0) 1762*14843421SMatthew Ahrens goto out; 1763*14843421SMatthew Ahrens if ((error = zfsvfs_hold(name, B_FALSE, FTAG, 1764*14843421SMatthew Ahrens &zfsvfs)) != 0) 1765*14843421SMatthew Ahrens goto out; 1766*14843421SMatthew Ahrens error = zfs_set_version(zfsvfs, intval); 1767*14843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 1768*14843421SMatthew Ahrens 1769*14843421SMatthew Ahrens if (error == 0 && intval >= ZPL_VERSION_USERSPACE) { 1770*14843421SMatthew Ahrens zfs_cmd_t zc = { 0 }; 1771*14843421SMatthew Ahrens (void) strcpy(zc.zc_name, name); 1772*14843421SMatthew Ahrens (void) zfs_ioc_userspace_upgrade(&zc); 1773*14843421SMatthew Ahrens } 1774*14843421SMatthew Ahrens if (error) 17755c0b6a79SRich Morris goto out; 1776e9dbad6fSeschrock break; 1777*14843421SMatthew Ahrens } 1778e9dbad6fSeschrock 1779e9dbad6fSeschrock default: 1780e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1781e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 17825c0b6a79SRich Morris PROP_TYPE_STRING) { 17835c0b6a79SRich Morris error = EINVAL; 17845c0b6a79SRich Morris goto out; 17855c0b6a79SRich Morris } 1786e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1787a2eea2e1Sahrens const char *unused; 1788a2eea2e1Sahrens 1789acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1790e9dbad6fSeschrock 1791e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 179291ebeef5Sahrens case PROP_TYPE_NUMBER: 1793e9dbad6fSeschrock break; 179491ebeef5Sahrens case PROP_TYPE_STRING: 17955c0b6a79SRich Morris error = EINVAL; 17965c0b6a79SRich Morris goto out; 179791ebeef5Sahrens case PROP_TYPE_INDEX: 1798acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 17995c0b6a79SRich Morris intval, &unused) != 0) { 18005c0b6a79SRich Morris error = EINVAL; 18015c0b6a79SRich Morris goto out; 18025c0b6a79SRich Morris } 1803e9dbad6fSeschrock break; 1804e9dbad6fSeschrock default: 1805e7437265Sahrens cmn_err(CE_PANIC, 1806e7437265Sahrens "unknown property type"); 1807e9dbad6fSeschrock break; 1808e9dbad6fSeschrock } 1809e9dbad6fSeschrock } else { 18105c0b6a79SRich Morris error = EINVAL; 18115c0b6a79SRich Morris goto out; 1812e9dbad6fSeschrock } 18135c0b6a79SRich Morris if ((error = nvlist_add_nvpair(genericnvl, elem)) != 0) 18145c0b6a79SRich Morris goto out; 1815e9dbad6fSeschrock } 1816e9dbad6fSeschrock } 1817e9dbad6fSeschrock 18185c0b6a79SRich Morris if (nvlist_next_nvpair(genericnvl, NULL) != NULL) { 18195c0b6a79SRich Morris error = dsl_props_set(name, genericnvl); 18205c0b6a79SRich Morris } 18215c0b6a79SRich Morris out: 18225c0b6a79SRich Morris nvlist_free(genericnvl); 18235c0b6a79SRich Morris return (error); 1824fa9e4066Sahrens } 1825fa9e4066Sahrens 1826ea2f5b9eSMatthew Ahrens /* 1827ea2f5b9eSMatthew Ahrens * Check that all the properties are valid user properties. 1828ea2f5b9eSMatthew Ahrens */ 1829ea2f5b9eSMatthew Ahrens static int 1830ea2f5b9eSMatthew Ahrens zfs_check_userprops(char *fsname, nvlist_t *nvl) 1831ea2f5b9eSMatthew Ahrens { 1832ea2f5b9eSMatthew Ahrens nvpair_t *elem = NULL; 1833ea2f5b9eSMatthew Ahrens int error = 0; 1834ea2f5b9eSMatthew Ahrens 1835ea2f5b9eSMatthew Ahrens while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1836ea2f5b9eSMatthew Ahrens const char *propname = nvpair_name(elem); 1837ea2f5b9eSMatthew Ahrens char *valstr; 1838ea2f5b9eSMatthew Ahrens 1839ea2f5b9eSMatthew Ahrens if (!zfs_prop_user(propname) || 1840ea2f5b9eSMatthew Ahrens nvpair_type(elem) != DATA_TYPE_STRING) 1841ea2f5b9eSMatthew Ahrens return (EINVAL); 1842ea2f5b9eSMatthew Ahrens 1843ea2f5b9eSMatthew Ahrens if (error = zfs_secpolicy_write_perms(fsname, 1844ea2f5b9eSMatthew Ahrens ZFS_DELEG_PERM_USERPROP, CRED())) 1845ea2f5b9eSMatthew Ahrens return (error); 1846ea2f5b9eSMatthew Ahrens 1847ea2f5b9eSMatthew Ahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 1848ea2f5b9eSMatthew Ahrens return (ENAMETOOLONG); 1849ea2f5b9eSMatthew Ahrens 1850ea2f5b9eSMatthew Ahrens VERIFY(nvpair_value_string(elem, &valstr) == 0); 1851ea2f5b9eSMatthew Ahrens if (strlen(valstr) >= ZAP_MAXVALUELEN) 1852ea2f5b9eSMatthew Ahrens return (E2BIG); 1853ea2f5b9eSMatthew Ahrens } 1854ea2f5b9eSMatthew Ahrens return (0); 1855ea2f5b9eSMatthew Ahrens } 1856ea2f5b9eSMatthew Ahrens 18573cb34c60Sahrens /* 18583cb34c60Sahrens * inputs: 18593cb34c60Sahrens * zc_name name of filesystem 18605c0b6a79SRich Morris * zc_value name of property to set 18613cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 1862bb0ade09Sahrens * zc_cookie clear existing local props? 18633cb34c60Sahrens * 18643cb34c60Sahrens * outputs: none 18653cb34c60Sahrens */ 1866fa9e4066Sahrens static int 1867e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1868fa9e4066Sahrens { 1869e9dbad6fSeschrock nvlist_t *nvl; 1870e9dbad6fSeschrock int error; 1871e9dbad6fSeschrock 1872990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1873990b4856Slling &nvl)) != 0) 1874e9dbad6fSeschrock return (error); 1875e9dbad6fSeschrock 1876bb0ade09Sahrens if (zc->zc_cookie) { 1877bb0ade09Sahrens nvlist_t *origprops; 1878bb0ade09Sahrens objset_t *os; 1879bb0ade09Sahrens 1880bb0ade09Sahrens if (dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1881bb0ade09Sahrens DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 1882bb0ade09Sahrens if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 18836e77af0aSDavid Pacheco clear_props(zc->zc_name, origprops, nvl); 1884bb0ade09Sahrens nvlist_free(origprops); 1885bb0ade09Sahrens } 1886bb0ade09Sahrens dmu_objset_close(os); 1887bb0ade09Sahrens } 1888bb0ade09Sahrens 1889bb0ade09Sahrens } 1890bb0ade09Sahrens 189191ebeef5Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1892ecd6cf80Smarks 1893e9dbad6fSeschrock nvlist_free(nvl); 1894e9dbad6fSeschrock return (error); 1895fa9e4066Sahrens } 1896fa9e4066Sahrens 18973cb34c60Sahrens /* 18983cb34c60Sahrens * inputs: 18993cb34c60Sahrens * zc_name name of filesystem 19003cb34c60Sahrens * zc_value name of property to inherit 19013cb34c60Sahrens * 19023cb34c60Sahrens * outputs: none 19033cb34c60Sahrens */ 1904e45ce728Sahrens static int 1905e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 1906e45ce728Sahrens { 1907e45ce728Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 1908e45ce728Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1909e45ce728Sahrens } 1910e45ce728Sahrens 1911b1b8ab34Slling static int 191211a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1913b1b8ab34Slling { 1914990b4856Slling nvlist_t *props; 1915b1b8ab34Slling spa_t *spa; 1916990b4856Slling int error; 1917379c004dSEric Schrock nvpair_t *elem; 1918b1b8ab34Slling 1919990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1920990b4856Slling &props))) 1921b1b8ab34Slling return (error); 1922b1b8ab34Slling 1923379c004dSEric Schrock /* 1924379c004dSEric Schrock * If the only property is the configfile, then just do a spa_lookup() 1925379c004dSEric Schrock * to handle the faulted case. 1926379c004dSEric Schrock */ 1927379c004dSEric Schrock elem = nvlist_next_nvpair(props, NULL); 1928379c004dSEric Schrock if (elem != NULL && strcmp(nvpair_name(elem), 1929379c004dSEric Schrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 1930379c004dSEric Schrock nvlist_next_nvpair(props, elem) == NULL) { 1931379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 1932379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) { 1933379c004dSEric Schrock spa_configfile_set(spa, props, B_FALSE); 1934379c004dSEric Schrock spa_config_sync(spa, B_FALSE, B_TRUE); 1935379c004dSEric Schrock } 1936379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 1937379c004dSEric Schrock if (spa != NULL) 1938379c004dSEric Schrock return (0); 1939379c004dSEric Schrock } 1940379c004dSEric Schrock 1941b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1942990b4856Slling nvlist_free(props); 1943b1b8ab34Slling return (error); 1944b1b8ab34Slling } 1945b1b8ab34Slling 1946990b4856Slling error = spa_prop_set(spa, props); 1947b1b8ab34Slling 1948990b4856Slling nvlist_free(props); 1949b1b8ab34Slling spa_close(spa, FTAG); 1950b1b8ab34Slling 1951b1b8ab34Slling return (error); 1952b1b8ab34Slling } 1953b1b8ab34Slling 1954b1b8ab34Slling static int 195511a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1956b1b8ab34Slling { 1957b1b8ab34Slling spa_t *spa; 1958b1b8ab34Slling int error; 1959b1b8ab34Slling nvlist_t *nvp = NULL; 1960b1b8ab34Slling 1961379c004dSEric Schrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1962379c004dSEric Schrock /* 1963379c004dSEric Schrock * If the pool is faulted, there may be properties we can still 1964379c004dSEric Schrock * get (such as altroot and cachefile), so attempt to get them 1965379c004dSEric Schrock * anyway. 1966379c004dSEric Schrock */ 1967379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 1968379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) 1969379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 1970379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 1971379c004dSEric Schrock } else { 1972379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 1973379c004dSEric Schrock spa_close(spa, FTAG); 1974379c004dSEric Schrock } 1975b1b8ab34Slling 1976b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1977b1b8ab34Slling error = put_nvlist(zc, nvp); 1978b1b8ab34Slling else 1979b1b8ab34Slling error = EFAULT; 1980b1b8ab34Slling 1981379c004dSEric Schrock nvlist_free(nvp); 1982b1b8ab34Slling return (error); 1983b1b8ab34Slling } 1984b1b8ab34Slling 1985ecd6cf80Smarks static int 1986ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1987ecd6cf80Smarks { 1988ecd6cf80Smarks nvlist_t *nvp; 1989ecd6cf80Smarks int error; 1990ecd6cf80Smarks uint32_t uid; 1991ecd6cf80Smarks uint32_t gid; 1992ecd6cf80Smarks uint32_t *groups; 1993ecd6cf80Smarks uint_t group_cnt; 1994ecd6cf80Smarks cred_t *usercred; 1995ecd6cf80Smarks 1996990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1997990b4856Slling &nvp)) != 0) { 1998ecd6cf80Smarks return (error); 1999ecd6cf80Smarks } 2000ecd6cf80Smarks 2001ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 2002ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 2003ecd6cf80Smarks nvlist_free(nvp); 2004ecd6cf80Smarks return (EPERM); 2005ecd6cf80Smarks } 2006ecd6cf80Smarks 2007ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 2008ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 2009ecd6cf80Smarks nvlist_free(nvp); 2010ecd6cf80Smarks return (EPERM); 2011ecd6cf80Smarks } 2012ecd6cf80Smarks 2013ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 2014ecd6cf80Smarks &groups, &group_cnt)) != 0) { 2015ecd6cf80Smarks nvlist_free(nvp); 2016ecd6cf80Smarks return (EPERM); 2017ecd6cf80Smarks } 2018ecd6cf80Smarks usercred = cralloc(); 2019ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 2020ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 2021ecd6cf80Smarks nvlist_free(nvp); 2022ecd6cf80Smarks crfree(usercred); 2023ecd6cf80Smarks return (EPERM); 2024ecd6cf80Smarks } 2025ecd6cf80Smarks nvlist_free(nvp); 2026ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 202791ebeef5Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 2028ecd6cf80Smarks crfree(usercred); 2029ecd6cf80Smarks return (error); 2030ecd6cf80Smarks } 2031ecd6cf80Smarks 20323cb34c60Sahrens /* 20333cb34c60Sahrens * inputs: 20343cb34c60Sahrens * zc_name name of filesystem 20353cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 20363cb34c60Sahrens * zc_perm_action allow/unallow flag 20373cb34c60Sahrens * 20383cb34c60Sahrens * outputs: none 20393cb34c60Sahrens */ 2040ecd6cf80Smarks static int 2041ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 2042ecd6cf80Smarks { 2043ecd6cf80Smarks int error; 2044ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 2045ecd6cf80Smarks 2046990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2047990b4856Slling &fsaclnv)) != 0) 2048ecd6cf80Smarks return (error); 2049ecd6cf80Smarks 2050ecd6cf80Smarks /* 2051ecd6cf80Smarks * Verify nvlist is constructed correctly 2052ecd6cf80Smarks */ 2053ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 2054ecd6cf80Smarks nvlist_free(fsaclnv); 2055ecd6cf80Smarks return (EINVAL); 2056ecd6cf80Smarks } 2057ecd6cf80Smarks 2058ecd6cf80Smarks /* 2059ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 2060ecd6cf80Smarks * that user is allowed to hand out each permission in 2061ecd6cf80Smarks * the nvlist(s) 2062ecd6cf80Smarks */ 2063ecd6cf80Smarks 206491ebeef5Sahrens error = secpolicy_zfs(CRED()); 2065ecd6cf80Smarks if (error) { 206691ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 206791ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 206891ebeef5Sahrens fsaclnv, CRED()); 206991ebeef5Sahrens } else { 207091ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 207191ebeef5Sahrens fsaclnv, CRED()); 207291ebeef5Sahrens } 2073ecd6cf80Smarks } 2074ecd6cf80Smarks 2075ecd6cf80Smarks if (error == 0) 2076ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 2077ecd6cf80Smarks 2078ecd6cf80Smarks nvlist_free(fsaclnv); 2079ecd6cf80Smarks return (error); 2080ecd6cf80Smarks } 2081ecd6cf80Smarks 20823cb34c60Sahrens /* 20833cb34c60Sahrens * inputs: 20843cb34c60Sahrens * zc_name name of filesystem 20853cb34c60Sahrens * 20863cb34c60Sahrens * outputs: 20873cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 20883cb34c60Sahrens */ 2089ecd6cf80Smarks static int 2090ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 2091ecd6cf80Smarks { 2092ecd6cf80Smarks nvlist_t *nvp; 2093ecd6cf80Smarks int error; 2094ecd6cf80Smarks 2095ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 2096ecd6cf80Smarks error = put_nvlist(zc, nvp); 2097ecd6cf80Smarks nvlist_free(nvp); 2098ecd6cf80Smarks } 2099ecd6cf80Smarks 2100ecd6cf80Smarks return (error); 2101ecd6cf80Smarks } 2102ecd6cf80Smarks 21033cb34c60Sahrens /* 21043cb34c60Sahrens * inputs: 21053cb34c60Sahrens * zc_name name of volume 21063cb34c60Sahrens * 21073cb34c60Sahrens * outputs: none 21083cb34c60Sahrens */ 2109fa9e4066Sahrens static int 2110fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 2111fa9e4066Sahrens { 211291ebeef5Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 2113fa9e4066Sahrens } 2114fa9e4066Sahrens 21153cb34c60Sahrens /* 21163cb34c60Sahrens * inputs: 21173cb34c60Sahrens * zc_name name of volume 21183cb34c60Sahrens * 21193cb34c60Sahrens * outputs: none 21203cb34c60Sahrens */ 2121fa9e4066Sahrens static int 2122fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 2123fa9e4066Sahrens { 2124e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 2125fa9e4066Sahrens } 2126fa9e4066Sahrens 2127fa9e4066Sahrens /* 2128fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 2129fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 2130fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 2131fa9e4066Sahrens */ 2132fa9e4066Sahrens static vfs_t * 2133fa9e4066Sahrens zfs_get_vfs(const char *resource) 2134fa9e4066Sahrens { 2135fa9e4066Sahrens struct vfs *vfsp; 2136fa9e4066Sahrens struct vfs *vfs_found = NULL; 2137fa9e4066Sahrens 2138fa9e4066Sahrens vfs_list_read_lock(); 2139fa9e4066Sahrens vfsp = rootvfs; 2140fa9e4066Sahrens do { 2141fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 2142fa9e4066Sahrens VFS_HOLD(vfsp); 2143fa9e4066Sahrens vfs_found = vfsp; 2144fa9e4066Sahrens break; 2145fa9e4066Sahrens } 2146fa9e4066Sahrens vfsp = vfsp->vfs_next; 2147fa9e4066Sahrens } while (vfsp != rootvfs); 2148fa9e4066Sahrens vfs_list_unlock(); 2149fa9e4066Sahrens return (vfs_found); 2150fa9e4066Sahrens } 2151fa9e4066Sahrens 2152ecd6cf80Smarks /* ARGSUSED */ 2153fa9e4066Sahrens static void 2154ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 2155fa9e4066Sahrens { 2156da6c28aaSamw zfs_creat_t *zct = arg; 2157da6c28aaSamw 2158de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 2159da6c28aaSamw } 2160da6c28aaSamw 2161de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 2162da6c28aaSamw 2163da6c28aaSamw /* 2164de8267e0Stimh * inputs: 21650a48a24eStimh * createprops list of properties requested by creator 21660a48a24eStimh * default_zplver zpl version to use if unspecified in createprops 21670a48a24eStimh * fuids_ok fuids allowed in this version of the spa? 21680a48a24eStimh * os parent objset pointer (NULL if root fs) 2169de8267e0Stimh * 2170de8267e0Stimh * outputs: 2171de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 21720a48a24eStimh * is_ci true if requested file system will be purely case-insensitive 2173da6c28aaSamw * 2174de8267e0Stimh * Determine the settings for utf8only, normalization and 2175de8267e0Stimh * casesensitivity. Specific values may have been requested by the 2176de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 2177de8267e0Stimh * the file system is of too early a vintage, a creator can not 2178de8267e0Stimh * request settings for these properties, even if the requested 2179de8267e0Stimh * setting is the default value. We don't actually want to create dsl 2180de8267e0Stimh * properties for these, so remove them from the source nvlist after 2181de8267e0Stimh * processing. 2182da6c28aaSamw */ 2183da6c28aaSamw static int 2184*14843421SMatthew Ahrens zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 21850a48a24eStimh boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 21860a48a24eStimh boolean_t *is_ci) 2187da6c28aaSamw { 2188de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 2189de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 2190de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 2191da6c28aaSamw 2192de8267e0Stimh ASSERT(zplprops != NULL); 2193da6c28aaSamw 2194de8267e0Stimh /* 2195de8267e0Stimh * Pull out creator prop choices, if any. 2196de8267e0Stimh */ 2197de8267e0Stimh if (createprops) { 21980a48a24eStimh (void) nvlist_lookup_uint64(createprops, 21990a48a24eStimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 2200de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 2201de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 2202de8267e0Stimh (void) nvlist_remove_all(createprops, 2203de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 2204de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 2205de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 2206de8267e0Stimh (void) nvlist_remove_all(createprops, 2207de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 2208de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 2209de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 2210de8267e0Stimh (void) nvlist_remove_all(createprops, 2211de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 2212de8267e0Stimh } 2213da6c28aaSamw 2214c2a93d44Stimh /* 22150a48a24eStimh * If the zpl version requested is whacky or the file system 22160a48a24eStimh * or pool is version is too "young" to support normalization 22170a48a24eStimh * and the creator tried to set a value for one of the props, 22180a48a24eStimh * error out. 2219c2a93d44Stimh */ 22200a48a24eStimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 22210a48a24eStimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 22220a48a24eStimh (zplver < ZPL_VERSION_NORMALIZATION && 2223de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 22240a48a24eStimh sense != ZFS_PROP_UNDEFINED))) 2225de8267e0Stimh return (ENOTSUP); 2226c2a93d44Stimh 2227de8267e0Stimh /* 2228de8267e0Stimh * Put the version in the zplprops 2229de8267e0Stimh */ 2230de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2231de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 2232da6c28aaSamw 2233de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 2234de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 2235de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2236de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 2237da6c28aaSamw 2238c2a93d44Stimh /* 2239de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 2240c2a93d44Stimh */ 2241de8267e0Stimh if (norm) 2242de8267e0Stimh u8 = 1; 2243de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 2244de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 2245de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2246de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 2247de8267e0Stimh 2248de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 2249de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 2250de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2251de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 2252c2a93d44Stimh 2253ab04eb8eStimh if (is_ci) 2254ab04eb8eStimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 2255ab04eb8eStimh 2256da6c28aaSamw return (0); 2257fa9e4066Sahrens } 2258fa9e4066Sahrens 22590a48a24eStimh static int 22600a48a24eStimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 22610a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 22620a48a24eStimh { 22630a48a24eStimh boolean_t fuids_ok = B_TRUE; 22640a48a24eStimh uint64_t zplver = ZPL_VERSION; 22650a48a24eStimh objset_t *os = NULL; 22660a48a24eStimh char parentname[MAXNAMELEN]; 22670a48a24eStimh char *cp; 22680a48a24eStimh int error; 22690a48a24eStimh 22700a48a24eStimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 22710a48a24eStimh cp = strrchr(parentname, '/'); 22720a48a24eStimh ASSERT(cp != NULL); 22730a48a24eStimh cp[0] = '\0'; 22740a48a24eStimh 2275*14843421SMatthew Ahrens if (zfs_earlier_version(dataset, SPA_VERSION_USERSPACE)) 2276*14843421SMatthew Ahrens zplver = ZPL_VERSION_USERSPACE - 1; 22770a48a24eStimh if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 22780a48a24eStimh zplver = ZPL_VERSION_FUID - 1; 22790a48a24eStimh fuids_ok = B_FALSE; 22800a48a24eStimh } 22810a48a24eStimh 22820a48a24eStimh /* 22830a48a24eStimh * Open parent object set so we can inherit zplprop values. 22840a48a24eStimh */ 22850a48a24eStimh if ((error = dmu_objset_open(parentname, DMU_OST_ANY, 22860a48a24eStimh DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) 22870a48a24eStimh return (error); 22880a48a24eStimh 22890a48a24eStimh error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 22900a48a24eStimh zplprops, is_ci); 22910a48a24eStimh dmu_objset_close(os); 22920a48a24eStimh return (error); 22930a48a24eStimh } 22940a48a24eStimh 22950a48a24eStimh static int 22960a48a24eStimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 22970a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 22980a48a24eStimh { 22990a48a24eStimh boolean_t fuids_ok = B_TRUE; 23000a48a24eStimh uint64_t zplver = ZPL_VERSION; 23010a48a24eStimh int error; 23020a48a24eStimh 23030a48a24eStimh if (spa_vers < SPA_VERSION_FUID) { 23040a48a24eStimh zplver = ZPL_VERSION_FUID - 1; 23050a48a24eStimh fuids_ok = B_FALSE; 23060a48a24eStimh } 23070a48a24eStimh 23080a48a24eStimh error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 23090a48a24eStimh zplprops, is_ci); 23100a48a24eStimh return (error); 23110a48a24eStimh } 23120a48a24eStimh 23133cb34c60Sahrens /* 23143cb34c60Sahrens * inputs: 23153cb34c60Sahrens * zc_objset_type type of objset to create (fs vs zvol) 23163cb34c60Sahrens * zc_name name of new objset 23173cb34c60Sahrens * zc_value name of snapshot to clone from (may be empty) 23183cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 23193cb34c60Sahrens * 2320de8267e0Stimh * outputs: none 23213cb34c60Sahrens */ 2322fa9e4066Sahrens static int 2323fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 2324fa9e4066Sahrens { 2325fa9e4066Sahrens objset_t *clone; 2326fa9e4066Sahrens int error = 0; 2327da6c28aaSamw zfs_creat_t zct; 2328ecd6cf80Smarks nvlist_t *nvprops = NULL; 2329ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2330fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 2331fa9e4066Sahrens 2332fa9e4066Sahrens switch (type) { 2333fa9e4066Sahrens 2334fa9e4066Sahrens case DMU_OST_ZFS: 2335fa9e4066Sahrens cbfunc = zfs_create_cb; 2336fa9e4066Sahrens break; 2337fa9e4066Sahrens 2338fa9e4066Sahrens case DMU_OST_ZVOL: 2339fa9e4066Sahrens cbfunc = zvol_create_cb; 2340fa9e4066Sahrens break; 2341fa9e4066Sahrens 2342fa9e4066Sahrens default: 23431d452cf5Sahrens cbfunc = NULL; 2344e7cbe64fSgw break; 2345fa9e4066Sahrens } 2346f18faf3fSek if (strchr(zc->zc_name, '@') || 2347f18faf3fSek strchr(zc->zc_name, '%')) 23481d452cf5Sahrens return (EINVAL); 2349fa9e4066Sahrens 2350e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 2351990b4856Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2352990b4856Slling &nvprops)) != 0) 2353e9dbad6fSeschrock return (error); 2354e9dbad6fSeschrock 2355de8267e0Stimh zct.zct_zplprops = NULL; 2356da6c28aaSamw zct.zct_props = nvprops; 2357da6c28aaSamw 2358e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 2359fa9e4066Sahrens /* 2360fa9e4066Sahrens * We're creating a clone of an existing snapshot. 2361fa9e4066Sahrens */ 2362e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2363e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 2364ecd6cf80Smarks nvlist_free(nvprops); 2365fa9e4066Sahrens return (EINVAL); 2366e9dbad6fSeschrock } 2367fa9e4066Sahrens 2368e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 2369745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 2370e9dbad6fSeschrock if (error) { 2371ecd6cf80Smarks nvlist_free(nvprops); 2372fa9e4066Sahrens return (error); 2373e9dbad6fSeschrock } 2374ab04eb8eStimh 2375ab04eb8eStimh error = dmu_objset_create(zc->zc_name, type, clone, 0, 2376ab04eb8eStimh NULL, NULL); 2377da6c28aaSamw if (error) { 2378da6c28aaSamw dmu_objset_close(clone); 2379da6c28aaSamw nvlist_free(nvprops); 2380da6c28aaSamw return (error); 2381da6c28aaSamw } 2382fa9e4066Sahrens dmu_objset_close(clone); 2383fa9e4066Sahrens } else { 2384ab04eb8eStimh boolean_t is_insensitive = B_FALSE; 2385ab04eb8eStimh 2386e9dbad6fSeschrock if (cbfunc == NULL) { 2387ecd6cf80Smarks nvlist_free(nvprops); 23881d452cf5Sahrens return (EINVAL); 2389e9dbad6fSeschrock } 23905c5460e9Seschrock 2391e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 2392e9dbad6fSeschrock uint64_t volsize, volblocksize; 2393e9dbad6fSeschrock 2394ecd6cf80Smarks if (nvprops == NULL || 2395ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 2396e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 2397e9dbad6fSeschrock &volsize) != 0) { 2398ecd6cf80Smarks nvlist_free(nvprops); 2399e9dbad6fSeschrock return (EINVAL); 2400e9dbad6fSeschrock } 2401e9dbad6fSeschrock 2402ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 2403e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2404e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 2405ecd6cf80Smarks nvlist_free(nvprops); 2406e9dbad6fSeschrock return (EINVAL); 2407e9dbad6fSeschrock } 2408e9dbad6fSeschrock 2409e9dbad6fSeschrock if (error != 0) 2410e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 2411e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 2412e9dbad6fSeschrock 2413e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 2414e9dbad6fSeschrock volblocksize)) != 0 || 2415e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 2416e9dbad6fSeschrock volblocksize)) != 0) { 2417ecd6cf80Smarks nvlist_free(nvprops); 24185c5460e9Seschrock return (error); 2419e9dbad6fSeschrock } 2420e7437265Sahrens } else if (type == DMU_OST_ZFS) { 2421da6c28aaSamw int error; 2422da6c28aaSamw 2423da6c28aaSamw /* 2424da6c28aaSamw * We have to have normalization and 2425da6c28aaSamw * case-folding flags correct when we do the 2426da6c28aaSamw * file system creation, so go figure them out 2427de8267e0Stimh * now. 2428da6c28aaSamw */ 2429de8267e0Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 2430de8267e0Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 2431de8267e0Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 24320a48a24eStimh zct.zct_zplprops, &is_insensitive); 2433da6c28aaSamw if (error != 0) { 2434da6c28aaSamw nvlist_free(nvprops); 2435de8267e0Stimh nvlist_free(zct.zct_zplprops); 2436da6c28aaSamw return (error); 2437da6c28aaSamw } 2438da6c28aaSamw } 2439ab04eb8eStimh error = dmu_objset_create(zc->zc_name, type, NULL, 2440ab04eb8eStimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 2441de8267e0Stimh nvlist_free(zct.zct_zplprops); 2442fa9e4066Sahrens } 2443e9dbad6fSeschrock 2444e9dbad6fSeschrock /* 2445e9dbad6fSeschrock * It would be nice to do this atomically. 2446e9dbad6fSeschrock */ 2447e9dbad6fSeschrock if (error == 0) { 244891ebeef5Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 2449e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 2450e9dbad6fSeschrock } 2451ecd6cf80Smarks nvlist_free(nvprops); 2452fa9e4066Sahrens return (error); 2453fa9e4066Sahrens } 2454fa9e4066Sahrens 24553cb34c60Sahrens /* 24563cb34c60Sahrens * inputs: 24573cb34c60Sahrens * zc_name name of filesystem 24583cb34c60Sahrens * zc_value short name of snapshot 24593cb34c60Sahrens * zc_cookie recursive flag 2460*14843421SMatthew Ahrens * zc_nvlist_src[_size] property list 24613cb34c60Sahrens * 24623cb34c60Sahrens * outputs: none 24633cb34c60Sahrens */ 2464fa9e4066Sahrens static int 24651d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 2466fa9e4066Sahrens { 2467bb0ade09Sahrens nvlist_t *nvprops = NULL; 2468bb0ade09Sahrens int error; 2469bb0ade09Sahrens boolean_t recursive = zc->zc_cookie; 2470bb0ade09Sahrens 2471e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 24721d452cf5Sahrens return (EINVAL); 2473bb0ade09Sahrens 2474bb0ade09Sahrens if (zc->zc_nvlist_src != NULL && 2475bb0ade09Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2476bb0ade09Sahrens &nvprops)) != 0) 2477bb0ade09Sahrens return (error); 2478bb0ade09Sahrens 2479ea2f5b9eSMatthew Ahrens error = zfs_check_userprops(zc->zc_name, nvprops); 2480ea2f5b9eSMatthew Ahrens if (error) 2481ea2f5b9eSMatthew Ahrens goto out; 2482bb0ade09Sahrens 2483ea2f5b9eSMatthew Ahrens if (nvprops != NULL && nvlist_next_nvpair(nvprops, NULL) != NULL && 2484ea2f5b9eSMatthew Ahrens zfs_earlier_version(zc->zc_name, SPA_VERSION_SNAP_PROPS)) { 2485ea2f5b9eSMatthew Ahrens error = ENOTSUP; 2486ea2f5b9eSMatthew Ahrens goto out; 2487bb0ade09Sahrens } 2488ea2f5b9eSMatthew Ahrens 2489ea2f5b9eSMatthew Ahrens error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, 2490ea2f5b9eSMatthew Ahrens nvprops, recursive); 2491ea2f5b9eSMatthew Ahrens 2492ea2f5b9eSMatthew Ahrens out: 2493bb0ade09Sahrens nvlist_free(nvprops); 2494bb0ade09Sahrens return (error); 24951d452cf5Sahrens } 2496fa9e4066Sahrens 2497cdf5b4caSmmusante int 24981d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 24991d452cf5Sahrens { 25000b69c2f0Sahrens vfs_t *vfsp = NULL; 25011d452cf5Sahrens 2502745cd3c5Smaybee if (arg) { 2503745cd3c5Smaybee char *snapname = arg; 2504745cd3c5Smaybee int len = strlen(name) + strlen(snapname) + 2; 2505745cd3c5Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 25061d452cf5Sahrens 2507745cd3c5Smaybee (void) strcpy(buf, name); 2508745cd3c5Smaybee (void) strcat(buf, "@"); 2509745cd3c5Smaybee (void) strcat(buf, snapname); 2510745cd3c5Smaybee vfsp = zfs_get_vfs(buf); 2511745cd3c5Smaybee kmem_free(buf, len); 25120b69c2f0Sahrens } else if (strchr(name, '@')) { 25131d452cf5Sahrens vfsp = zfs_get_vfs(name); 25141d452cf5Sahrens } 25151d452cf5Sahrens 25161d452cf5Sahrens if (vfsp) { 2517fa9e4066Sahrens /* 25181d452cf5Sahrens * Always force the unmount for snapshots. 2519fa9e4066Sahrens */ 25201d452cf5Sahrens int flag = MS_FORCE; 25211d452cf5Sahrens int err; 25221d452cf5Sahrens 25231d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 2524fa9e4066Sahrens VFS_RELE(vfsp); 25251d452cf5Sahrens return (err); 2526fa9e4066Sahrens } 25271d452cf5Sahrens VFS_RELE(vfsp); 25281d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 25291d452cf5Sahrens return (err); 25301d452cf5Sahrens } 25311d452cf5Sahrens return (0); 25321d452cf5Sahrens } 25331d452cf5Sahrens 25343cb34c60Sahrens /* 25353cb34c60Sahrens * inputs: 25363cb34c60Sahrens * zc_name name of filesystem 25373cb34c60Sahrens * zc_value short name of snapshot 25383cb34c60Sahrens * 25393cb34c60Sahrens * outputs: none 25403cb34c60Sahrens */ 25411d452cf5Sahrens static int 25421d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 25431d452cf5Sahrens { 25441d452cf5Sahrens int err; 25451d452cf5Sahrens 2546e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 25471d452cf5Sahrens return (EINVAL); 25481d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 2549e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 25501d452cf5Sahrens if (err) 25511d452cf5Sahrens return (err); 2552e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 25531d452cf5Sahrens } 25541d452cf5Sahrens 25553cb34c60Sahrens /* 25563cb34c60Sahrens * inputs: 25573cb34c60Sahrens * zc_name name of dataset to destroy 25583cb34c60Sahrens * zc_objset_type type of objset 25593cb34c60Sahrens * 25603cb34c60Sahrens * outputs: none 25613cb34c60Sahrens */ 25621d452cf5Sahrens static int 25631d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 25641d452cf5Sahrens { 25651d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 25661d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 25671d452cf5Sahrens if (err) 25681d452cf5Sahrens return (err); 2569fa9e4066Sahrens } 2570fa9e4066Sahrens 2571fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 2572fa9e4066Sahrens } 2573fa9e4066Sahrens 25743cb34c60Sahrens /* 25753cb34c60Sahrens * inputs: 25764ccbb6e7Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 25773cb34c60Sahrens * 25783cb34c60Sahrens * outputs: none 25793cb34c60Sahrens */ 2580fa9e4066Sahrens static int 2581fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2582fa9e4066Sahrens { 25834ccbb6e7Sahrens objset_t *os; 25844ccbb6e7Sahrens int error; 25854ccbb6e7Sahrens zfsvfs_t *zfsvfs = NULL; 25864ccbb6e7Sahrens 25874ccbb6e7Sahrens /* 25884ccbb6e7Sahrens * Get the zfsvfs for the receiving objset. There 25894ccbb6e7Sahrens * won't be one if we're operating on a zvol, if the 25904ccbb6e7Sahrens * objset doesn't exist yet, or is not mounted. 25914ccbb6e7Sahrens */ 2592745cd3c5Smaybee error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, DS_MODE_USER, &os); 25934ccbb6e7Sahrens if (error) 25944ccbb6e7Sahrens return (error); 25954ccbb6e7Sahrens 2596*14843421SMatthew Ahrens if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 25974ccbb6e7Sahrens int mode; 25984ccbb6e7Sahrens 2599*14843421SMatthew Ahrens error = zfs_suspend_fs(zfsvfs, NULL, &mode); 260047f263f4Sek if (error == 0) { 260147f263f4Sek int resume_err; 26024ccbb6e7Sahrens 260347f263f4Sek error = dmu_objset_rollback(os); 2604*14843421SMatthew Ahrens resume_err = zfs_resume_fs(zfsvfs, zc->zc_name, mode); 260547f263f4Sek error = error ? error : resume_err; 260647f263f4Sek } else { 260747f263f4Sek dmu_objset_close(os); 260847f263f4Sek } 26094ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 26104ccbb6e7Sahrens } else { 26114ccbb6e7Sahrens error = dmu_objset_rollback(os); 26124ccbb6e7Sahrens } 2613745cd3c5Smaybee /* Note, the dmu_objset_rollback() releases the objset for us. */ 26144ccbb6e7Sahrens 26154ccbb6e7Sahrens return (error); 2616fa9e4066Sahrens } 2617fa9e4066Sahrens 26183cb34c60Sahrens /* 26193cb34c60Sahrens * inputs: 26203cb34c60Sahrens * zc_name old name of dataset 26213cb34c60Sahrens * zc_value new name of dataset 26223cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 26233cb34c60Sahrens * 26243cb34c60Sahrens * outputs: none 26253cb34c60Sahrens */ 2626fa9e4066Sahrens static int 2627fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2628fa9e4066Sahrens { 26297f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 2630cdf5b4caSmmusante 2631e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2632f18faf3fSek if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2633f18faf3fSek strchr(zc->zc_value, '%')) 2634fa9e4066Sahrens return (EINVAL); 2635fa9e4066Sahrens 2636cdf5b4caSmmusante /* 2637cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 2638cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 2639cdf5b4caSmmusante * to unmount. 2640cdf5b4caSmmusante */ 2641cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2642fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 26431d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 26441d452cf5Sahrens if (err) 26451d452cf5Sahrens return (err); 2646fa9e4066Sahrens } 2647cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2648fa9e4066Sahrens } 2649fa9e4066Sahrens 2650745cd3c5Smaybee static void 26516e77af0aSDavid Pacheco clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops) 2652745cd3c5Smaybee { 2653745cd3c5Smaybee zfs_cmd_t *zc; 2654745cd3c5Smaybee nvpair_t *prop; 2655745cd3c5Smaybee 2656745cd3c5Smaybee if (props == NULL) 2657745cd3c5Smaybee return; 2658745cd3c5Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 2659745cd3c5Smaybee (void) strcpy(zc->zc_name, dataset); 2660745cd3c5Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 2661745cd3c5Smaybee prop = nvlist_next_nvpair(props, prop)) { 26626e77af0aSDavid Pacheco if (newprops != NULL && 26636e77af0aSDavid Pacheco nvlist_exists(newprops, nvpair_name(prop))) 26646e77af0aSDavid Pacheco continue; 2665745cd3c5Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 2666745cd3c5Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 2667745cd3c5Smaybee (void) zfs_ioc_inherit_prop(zc); 2668745cd3c5Smaybee } 2669745cd3c5Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 2670745cd3c5Smaybee } 2671745cd3c5Smaybee 26723cb34c60Sahrens /* 26733cb34c60Sahrens * inputs: 26743cb34c60Sahrens * zc_name name of containing filesystem 26753cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 26763cb34c60Sahrens * zc_value name of snapshot to create 26773cb34c60Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 26783cb34c60Sahrens * zc_cookie file descriptor to recv from 26793cb34c60Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 26803cb34c60Sahrens * zc_guid force flag 26813cb34c60Sahrens * 26823cb34c60Sahrens * outputs: 26833cb34c60Sahrens * zc_cookie number of bytes read 26843cb34c60Sahrens */ 2685fa9e4066Sahrens static int 26863cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2687fa9e4066Sahrens { 2688fa9e4066Sahrens file_t *fp; 2689f18faf3fSek objset_t *os; 26903cb34c60Sahrens dmu_recv_cookie_t drc; 2691f18faf3fSek zfsvfs_t *zfsvfs = NULL; 2692f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 2693f18faf3fSek int error, fd; 26943cb34c60Sahrens offset_t off; 26953cb34c60Sahrens nvlist_t *props = NULL; 2696745cd3c5Smaybee nvlist_t *origprops = NULL; 26973cb34c60Sahrens objset_t *origin = NULL; 26983cb34c60Sahrens char *tosnap; 26993cb34c60Sahrens char tofs[ZFS_MAXNAMELEN]; 2700fa9e4066Sahrens 27013ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2702f18faf3fSek strchr(zc->zc_value, '@') == NULL || 2703f18faf3fSek strchr(zc->zc_value, '%')) 27043ccfa83cSahrens return (EINVAL); 27053ccfa83cSahrens 27063cb34c60Sahrens (void) strcpy(tofs, zc->zc_value); 27073cb34c60Sahrens tosnap = strchr(tofs, '@'); 27083cb34c60Sahrens *tosnap = '\0'; 27093cb34c60Sahrens tosnap++; 27103cb34c60Sahrens 27113cb34c60Sahrens if (zc->zc_nvlist_src != NULL && 27123cb34c60Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 27133cb34c60Sahrens &props)) != 0) 27143cb34c60Sahrens return (error); 27153cb34c60Sahrens 2716fa9e4066Sahrens fd = zc->zc_cookie; 2717fa9e4066Sahrens fp = getf(fd); 27183cb34c60Sahrens if (fp == NULL) { 27193cb34c60Sahrens nvlist_free(props); 2720fa9e4066Sahrens return (EBADF); 27213cb34c60Sahrens } 2722f18faf3fSek 2723*14843421SMatthew Ahrens if (getzfsvfs(tofs, &zfsvfs) == 0) { 2724*14843421SMatthew Ahrens if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) { 2725*14843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 2726*14843421SMatthew Ahrens zfsvfs = NULL; 2727*14843421SMatthew Ahrens error = EBUSY; 2728*14843421SMatthew Ahrens goto out; 272947f263f4Sek } 2730745cd3c5Smaybee /* 2731745cd3c5Smaybee * If new properties are supplied, they are to completely 2732745cd3c5Smaybee * replace the existing ones, so stash away the existing ones. 2733745cd3c5Smaybee */ 2734745cd3c5Smaybee if (props) 2735*14843421SMatthew Ahrens (void) dsl_prop_get_all(zfsvfs->z_os, &origprops, TRUE); 2736*14843421SMatthew Ahrens } else if (props && dmu_objset_open(tofs, DMU_OST_ANY, 2737*14843421SMatthew Ahrens DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 2738*14843421SMatthew Ahrens /* 2739*14843421SMatthew Ahrens * Get the props even if there was no zfsvfs (zvol or 2740*14843421SMatthew Ahrens * unmounted zpl). 2741*14843421SMatthew Ahrens */ 2742*14843421SMatthew Ahrens (void) dsl_prop_get_all(os, &origprops, TRUE); 2743745cd3c5Smaybee 2744f18faf3fSek dmu_objset_close(os); 2745f18faf3fSek } 2746f18faf3fSek 27473cb34c60Sahrens if (zc->zc_string[0]) { 27483cb34c60Sahrens error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 2749745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &origin); 2750745cd3c5Smaybee if (error) 2751745cd3c5Smaybee goto out; 27523cb34c60Sahrens } 27533cb34c60Sahrens 27543cb34c60Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 27553cb34c60Sahrens force, origin, zfsvfs != NULL, &drc); 27563cb34c60Sahrens if (origin) 27573cb34c60Sahrens dmu_objset_close(origin); 2758745cd3c5Smaybee if (error) 2759745cd3c5Smaybee goto out; 2760f18faf3fSek 2761f18faf3fSek /* 2762745cd3c5Smaybee * Reset properties. We do this before we receive the stream 2763745cd3c5Smaybee * so that the properties are applied to the new data. 2764f18faf3fSek */ 27653cb34c60Sahrens if (props) { 27666e77af0aSDavid Pacheco clear_props(tofs, origprops, props); 2767745cd3c5Smaybee /* 2768745cd3c5Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 2769745cd3c5Smaybee */ 2770745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, props); 27713cb34c60Sahrens } 27723cb34c60Sahrens 27733cb34c60Sahrens off = fp->f_offset; 27743cb34c60Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 2775a2eea2e1Sahrens 2776745cd3c5Smaybee if (error == 0 && zfsvfs) { 27776a0f0066SEric Taylor char *osname; 2778745cd3c5Smaybee int mode; 2779745cd3c5Smaybee 2780745cd3c5Smaybee /* online recv */ 27816a0f0066SEric Taylor osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 2782745cd3c5Smaybee error = zfs_suspend_fs(zfsvfs, osname, &mode); 2783745cd3c5Smaybee if (error == 0) { 2784745cd3c5Smaybee int resume_err; 2785745cd3c5Smaybee 27863cb34c60Sahrens error = dmu_recv_end(&drc); 2787745cd3c5Smaybee resume_err = zfs_resume_fs(zfsvfs, osname, mode); 2788745cd3c5Smaybee error = error ? error : resume_err; 2789745cd3c5Smaybee } else { 2790745cd3c5Smaybee dmu_recv_abort_cleanup(&drc); 27913cb34c60Sahrens } 27926a0f0066SEric Taylor kmem_free(osname, MAXNAMELEN); 2793745cd3c5Smaybee } else if (error == 0) { 2794745cd3c5Smaybee error = dmu_recv_end(&drc); 279547f263f4Sek } 27963cb34c60Sahrens 27973cb34c60Sahrens zc->zc_cookie = off - fp->f_offset; 27983cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 27993cb34c60Sahrens fp->f_offset = off; 2800a2eea2e1Sahrens 2801745cd3c5Smaybee /* 2802745cd3c5Smaybee * On error, restore the original props. 2803745cd3c5Smaybee */ 2804745cd3c5Smaybee if (error && props) { 28056e77af0aSDavid Pacheco clear_props(tofs, props, NULL); 2806745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 2807745cd3c5Smaybee } 2808745cd3c5Smaybee out: 2809745cd3c5Smaybee if (zfsvfs) { 2810745cd3c5Smaybee mutex_exit(&zfsvfs->z_online_recv_lock); 2811745cd3c5Smaybee VFS_RELE(zfsvfs->z_vfs); 2812745cd3c5Smaybee } 2813745cd3c5Smaybee nvlist_free(props); 2814745cd3c5Smaybee nvlist_free(origprops); 2815fa9e4066Sahrens releasef(fd); 2816fa9e4066Sahrens return (error); 2817fa9e4066Sahrens } 2818fa9e4066Sahrens 28193cb34c60Sahrens /* 28203cb34c60Sahrens * inputs: 28213cb34c60Sahrens * zc_name name of snapshot to send 28223cb34c60Sahrens * zc_value short name of incremental fromsnap (may be empty) 28233cb34c60Sahrens * zc_cookie file descriptor to send stream to 28243cb34c60Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 28253cb34c60Sahrens * 28263cb34c60Sahrens * outputs: none 28273cb34c60Sahrens */ 2828fa9e4066Sahrens static int 28293cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2830fa9e4066Sahrens { 2831fa9e4066Sahrens objset_t *fromsnap = NULL; 2832fa9e4066Sahrens objset_t *tosnap; 2833fa9e4066Sahrens file_t *fp; 2834fa9e4066Sahrens int error; 28353cb34c60Sahrens offset_t off; 2836fa9e4066Sahrens 2837fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 2838745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &tosnap); 2839fa9e4066Sahrens if (error) 2840fa9e4066Sahrens return (error); 2841fa9e4066Sahrens 2842e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 28436a0f0066SEric Taylor char *buf; 2844a2eea2e1Sahrens char *cp; 2845a2eea2e1Sahrens 28466a0f0066SEric Taylor buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 28476a0f0066SEric Taylor (void) strncpy(buf, zc->zc_name, MAXPATHLEN); 2848a2eea2e1Sahrens cp = strchr(buf, '@'); 2849a2eea2e1Sahrens if (cp) 2850a2eea2e1Sahrens *(cp+1) = 0; 28516a0f0066SEric Taylor (void) strncat(buf, zc->zc_value, MAXPATHLEN); 2852a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 2853745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &fromsnap); 28546a0f0066SEric Taylor kmem_free(buf, MAXPATHLEN); 2855fa9e4066Sahrens if (error) { 2856fa9e4066Sahrens dmu_objset_close(tosnap); 2857fa9e4066Sahrens return (error); 2858fa9e4066Sahrens } 2859fa9e4066Sahrens } 2860fa9e4066Sahrens 2861fa9e4066Sahrens fp = getf(zc->zc_cookie); 2862fa9e4066Sahrens if (fp == NULL) { 2863fa9e4066Sahrens dmu_objset_close(tosnap); 2864fa9e4066Sahrens if (fromsnap) 2865fa9e4066Sahrens dmu_objset_close(fromsnap); 2866fa9e4066Sahrens return (EBADF); 2867fa9e4066Sahrens } 2868fa9e4066Sahrens 28693cb34c60Sahrens off = fp->f_offset; 28703cb34c60Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 2871fa9e4066Sahrens 28723cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 28733cb34c60Sahrens fp->f_offset = off; 2874fa9e4066Sahrens releasef(zc->zc_cookie); 2875fa9e4066Sahrens if (fromsnap) 2876fa9e4066Sahrens dmu_objset_close(fromsnap); 2877fa9e4066Sahrens dmu_objset_close(tosnap); 2878fa9e4066Sahrens return (error); 2879fa9e4066Sahrens } 2880fa9e4066Sahrens 2881ea8dc4b6Seschrock static int 2882ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 2883ea8dc4b6Seschrock { 2884ea8dc4b6Seschrock int id, error; 2885ea8dc4b6Seschrock 2886ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2887ea8dc4b6Seschrock &zc->zc_inject_record); 2888ea8dc4b6Seschrock 2889ea8dc4b6Seschrock if (error == 0) 2890ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 2891ea8dc4b6Seschrock 2892ea8dc4b6Seschrock return (error); 2893ea8dc4b6Seschrock } 2894ea8dc4b6Seschrock 2895ea8dc4b6Seschrock static int 2896ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 2897ea8dc4b6Seschrock { 2898ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 2899ea8dc4b6Seschrock } 2900ea8dc4b6Seschrock 2901ea8dc4b6Seschrock static int 2902ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2903ea8dc4b6Seschrock { 2904ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2905ea8dc4b6Seschrock int error; 2906ea8dc4b6Seschrock 2907ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2908ea8dc4b6Seschrock &zc->zc_inject_record); 2909ea8dc4b6Seschrock 2910ea8dc4b6Seschrock zc->zc_guid = id; 2911ea8dc4b6Seschrock 2912ea8dc4b6Seschrock return (error); 2913ea8dc4b6Seschrock } 2914ea8dc4b6Seschrock 2915ea8dc4b6Seschrock static int 2916ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2917ea8dc4b6Seschrock { 2918ea8dc4b6Seschrock spa_t *spa; 2919ea8dc4b6Seschrock int error; 2920e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2921ea8dc4b6Seschrock 2922ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2923ea8dc4b6Seschrock return (error); 2924ea8dc4b6Seschrock 2925e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2926ea8dc4b6Seschrock &count); 2927ea8dc4b6Seschrock if (error == 0) 2928e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2929ea8dc4b6Seschrock else 2930e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2931ea8dc4b6Seschrock 2932ea8dc4b6Seschrock spa_close(spa, FTAG); 2933ea8dc4b6Seschrock 2934ea8dc4b6Seschrock return (error); 2935ea8dc4b6Seschrock } 2936ea8dc4b6Seschrock 2937ea8dc4b6Seschrock static int 2938ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2939ea8dc4b6Seschrock { 2940ea8dc4b6Seschrock spa_t *spa; 2941ea8dc4b6Seschrock vdev_t *vd; 2942bb8b5132Sek int error; 2943ea8dc4b6Seschrock 2944b87f3af3Sperrin /* 2945b87f3af3Sperrin * On zpool clear we also fix up missing slogs 2946b87f3af3Sperrin */ 2947b87f3af3Sperrin mutex_enter(&spa_namespace_lock); 2948b87f3af3Sperrin spa = spa_lookup(zc->zc_name); 2949b87f3af3Sperrin if (spa == NULL) { 2950b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 2951b87f3af3Sperrin return (EIO); 2952b87f3af3Sperrin } 2953b87f3af3Sperrin if (spa->spa_log_state == SPA_LOG_MISSING) { 2954b87f3af3Sperrin /* we need to let spa_open/spa_load clear the chains */ 2955b87f3af3Sperrin spa->spa_log_state = SPA_LOG_CLEAR; 2956b87f3af3Sperrin } 2957b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 2958b87f3af3Sperrin 2959ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2960ea8dc4b6Seschrock return (error); 2961ea8dc4b6Seschrock 2962e14bb325SJeff Bonwick spa_vdev_state_enter(spa); 2963ea8dc4b6Seschrock 2964e9dbad6fSeschrock if (zc->zc_guid == 0) { 2965ea8dc4b6Seschrock vd = NULL; 2966c5904d13Seschrock } else { 2967c5904d13Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 2968fa94a07fSbrendan if (vd == NULL) { 2969e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, ENODEV); 2970fa94a07fSbrendan spa_close(spa, FTAG); 2971fa94a07fSbrendan return (ENODEV); 2972fa94a07fSbrendan } 2973ea8dc4b6Seschrock } 2974ea8dc4b6Seschrock 2975e14bb325SJeff Bonwick vdev_clear(spa, vd); 2976e14bb325SJeff Bonwick 2977e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, 0); 2978ea8dc4b6Seschrock 2979e14bb325SJeff Bonwick /* 2980e14bb325SJeff Bonwick * Resume any suspended I/Os. 2981e14bb325SJeff Bonwick */ 298254d692b7SGeorge Wilson if (zio_resume(spa) != 0) 298354d692b7SGeorge Wilson error = EIO; 2984ea8dc4b6Seschrock 2985ea8dc4b6Seschrock spa_close(spa, FTAG); 2986ea8dc4b6Seschrock 298754d692b7SGeorge Wilson return (error); 2988ea8dc4b6Seschrock } 2989ea8dc4b6Seschrock 29903cb34c60Sahrens /* 29913cb34c60Sahrens * inputs: 29923cb34c60Sahrens * zc_name name of filesystem 29933cb34c60Sahrens * zc_value name of origin snapshot 29943cb34c60Sahrens * 29953cb34c60Sahrens * outputs: none 29963cb34c60Sahrens */ 299799653d4eSeschrock static int 299899653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 299999653d4eSeschrock { 30000b69c2f0Sahrens char *cp; 30010b69c2f0Sahrens 30020b69c2f0Sahrens /* 30030b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 30040b69c2f0Sahrens * it's easier. 30050b69c2f0Sahrens */ 3006e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 30070b69c2f0Sahrens if (cp) 30080b69c2f0Sahrens *cp = '\0'; 3009e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 30100b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 301199653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 301299653d4eSeschrock } 301399653d4eSeschrock 3014*14843421SMatthew Ahrens /* 3015*14843421SMatthew Ahrens * Retrieve a single {user|group}{used|quota}@... property. 3016*14843421SMatthew Ahrens * 3017*14843421SMatthew Ahrens * inputs: 3018*14843421SMatthew Ahrens * zc_name name of filesystem 3019*14843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 3020*14843421SMatthew Ahrens * zc_value domain name (eg. "S-1-234-567-89") 3021*14843421SMatthew Ahrens * zc_guid RID/UID/GID 3022*14843421SMatthew Ahrens * 3023*14843421SMatthew Ahrens * outputs: 3024*14843421SMatthew Ahrens * zc_cookie property value 3025*14843421SMatthew Ahrens */ 3026*14843421SMatthew Ahrens static int 3027*14843421SMatthew Ahrens zfs_ioc_userspace_one(zfs_cmd_t *zc) 3028*14843421SMatthew Ahrens { 3029*14843421SMatthew Ahrens zfsvfs_t *zfsvfs; 3030*14843421SMatthew Ahrens int error; 3031*14843421SMatthew Ahrens 3032*14843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 3033*14843421SMatthew Ahrens return (EINVAL); 3034*14843421SMatthew Ahrens 3035*14843421SMatthew Ahrens error = zfsvfs_hold(zc->zc_name, B_TRUE, FTAG, &zfsvfs); 3036*14843421SMatthew Ahrens if (error) 3037*14843421SMatthew Ahrens return (error); 3038*14843421SMatthew Ahrens 3039*14843421SMatthew Ahrens error = zfs_userspace_one(zfsvfs, 3040*14843421SMatthew Ahrens zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 3041*14843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 3042*14843421SMatthew Ahrens 3043*14843421SMatthew Ahrens return (error); 3044*14843421SMatthew Ahrens } 3045*14843421SMatthew Ahrens 3046*14843421SMatthew Ahrens /* 3047*14843421SMatthew Ahrens * inputs: 3048*14843421SMatthew Ahrens * zc_name name of filesystem 3049*14843421SMatthew Ahrens * zc_cookie zap cursor 3050*14843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 3051*14843421SMatthew Ahrens * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 3052*14843421SMatthew Ahrens * 3053*14843421SMatthew Ahrens * outputs: 3054*14843421SMatthew Ahrens * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 3055*14843421SMatthew Ahrens * zc_cookie zap cursor 3056*14843421SMatthew Ahrens */ 3057*14843421SMatthew Ahrens static int 3058*14843421SMatthew Ahrens zfs_ioc_userspace_many(zfs_cmd_t *zc) 3059*14843421SMatthew Ahrens { 3060*14843421SMatthew Ahrens zfsvfs_t *zfsvfs; 3061*14843421SMatthew Ahrens int error; 3062*14843421SMatthew Ahrens 3063*14843421SMatthew Ahrens error = zfsvfs_hold(zc->zc_name, B_TRUE, FTAG, &zfsvfs); 3064*14843421SMatthew Ahrens if (error) 3065*14843421SMatthew Ahrens return (error); 3066*14843421SMatthew Ahrens 3067*14843421SMatthew Ahrens int bufsize = zc->zc_nvlist_dst_size; 3068*14843421SMatthew Ahrens void *buf = kmem_alloc(bufsize, KM_SLEEP); 3069*14843421SMatthew Ahrens 3070*14843421SMatthew Ahrens error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 3071*14843421SMatthew Ahrens buf, &zc->zc_nvlist_dst_size); 3072*14843421SMatthew Ahrens 3073*14843421SMatthew Ahrens if (error == 0) { 3074*14843421SMatthew Ahrens error = xcopyout(buf, 3075*14843421SMatthew Ahrens (void *)(uintptr_t)zc->zc_nvlist_dst, 3076*14843421SMatthew Ahrens zc->zc_nvlist_dst_size); 3077*14843421SMatthew Ahrens } 3078*14843421SMatthew Ahrens kmem_free(buf, bufsize); 3079*14843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 3080*14843421SMatthew Ahrens 3081*14843421SMatthew Ahrens return (error); 3082*14843421SMatthew Ahrens } 3083*14843421SMatthew Ahrens 3084*14843421SMatthew Ahrens /* 3085*14843421SMatthew Ahrens * inputs: 3086*14843421SMatthew Ahrens * zc_name name of filesystem 3087*14843421SMatthew Ahrens * 3088*14843421SMatthew Ahrens * outputs: 3089*14843421SMatthew Ahrens * none 3090*14843421SMatthew Ahrens */ 3091*14843421SMatthew Ahrens static int 3092*14843421SMatthew Ahrens zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 3093*14843421SMatthew Ahrens { 3094*14843421SMatthew Ahrens objset_t *os; 3095*14843421SMatthew Ahrens int error; 3096*14843421SMatthew Ahrens zfsvfs_t *zfsvfs; 3097*14843421SMatthew Ahrens 3098*14843421SMatthew Ahrens if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 3099*14843421SMatthew Ahrens if (!dmu_objset_userused_enabled(zfsvfs->z_os->os)) { 3100*14843421SMatthew Ahrens /* 3101*14843421SMatthew Ahrens * If userused is not enabled, it may be because the 3102*14843421SMatthew Ahrens * objset needs to be closed & reopened (to grow the 3103*14843421SMatthew Ahrens * objset_phys_t). Suspend/resume the fs will do that. 3104*14843421SMatthew Ahrens */ 3105*14843421SMatthew Ahrens int mode; 3106*14843421SMatthew Ahrens error = zfs_suspend_fs(zfsvfs, NULL, &mode); 3107*14843421SMatthew Ahrens if (error == 0) { 3108*14843421SMatthew Ahrens error = zfs_resume_fs(zfsvfs, 3109*14843421SMatthew Ahrens zc->zc_name, mode); 3110*14843421SMatthew Ahrens } 3111*14843421SMatthew Ahrens } 3112*14843421SMatthew Ahrens if (error == 0) 3113*14843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 3114*14843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 3115*14843421SMatthew Ahrens } else { 3116*14843421SMatthew Ahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 3117*14843421SMatthew Ahrens DS_MODE_USER, &os); 3118*14843421SMatthew Ahrens if (error) 3119*14843421SMatthew Ahrens return (error); 3120*14843421SMatthew Ahrens 3121*14843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(os); 3122*14843421SMatthew Ahrens dmu_objset_close(os); 3123*14843421SMatthew Ahrens } 3124*14843421SMatthew Ahrens 3125*14843421SMatthew Ahrens return (error); 3126*14843421SMatthew Ahrens } 3127*14843421SMatthew Ahrens 3128ecd6cf80Smarks /* 3129ecd6cf80Smarks * We don't want to have a hard dependency 3130ecd6cf80Smarks * against some special symbols in sharefs 3131da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 3132ecd6cf80Smarks * the first file system is shared. 3133da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 3134ecd6cf80Smarks */ 3135da6c28aaSamw int (*znfsexport_fs)(void *arg); 3136ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 3137da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 3138da6c28aaSamw 3139da6c28aaSamw int zfs_nfsshare_inited; 3140da6c28aaSamw int zfs_smbshare_inited; 3141ecd6cf80Smarks 3142ecd6cf80Smarks ddi_modhandle_t nfs_mod; 3143ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 3144da6c28aaSamw ddi_modhandle_t smbsrv_mod; 3145ecd6cf80Smarks kmutex_t zfs_share_lock; 3146ecd6cf80Smarks 3147da6c28aaSamw static int 3148da6c28aaSamw zfs_init_sharefs() 3149da6c28aaSamw { 3150da6c28aaSamw int error; 3151da6c28aaSamw 3152da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 3153da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 3154da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 3155da6c28aaSamw ddi_modopen("fs/sharefs", 3156da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 3157da6c28aaSamw return (ENOSYS); 3158da6c28aaSamw } 3159da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 3160da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 3161da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 3162da6c28aaSamw return (ENOSYS); 3163da6c28aaSamw } 3164da6c28aaSamw return (0); 3165da6c28aaSamw } 3166da6c28aaSamw 3167ecd6cf80Smarks static int 3168ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 3169ecd6cf80Smarks { 3170ecd6cf80Smarks int error; 3171ecd6cf80Smarks int opcode; 3172ecd6cf80Smarks 3173da6c28aaSamw switch (zc->zc_share.z_sharetype) { 3174da6c28aaSamw case ZFS_SHARE_NFS: 3175da6c28aaSamw case ZFS_UNSHARE_NFS: 3176da6c28aaSamw if (zfs_nfsshare_inited == 0) { 3177da6c28aaSamw mutex_enter(&zfs_share_lock); 3178da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 3179da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 3180da6c28aaSamw mutex_exit(&zfs_share_lock); 3181da6c28aaSamw return (ENOSYS); 3182da6c28aaSamw } 3183da6c28aaSamw if (znfsexport_fs == NULL && 3184da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 3185da6c28aaSamw ddi_modsym(nfs_mod, 3186da6c28aaSamw "nfs_export", &error)) == NULL)) { 3187da6c28aaSamw mutex_exit(&zfs_share_lock); 3188da6c28aaSamw return (ENOSYS); 3189da6c28aaSamw } 3190da6c28aaSamw error = zfs_init_sharefs(); 3191da6c28aaSamw if (error) { 3192da6c28aaSamw mutex_exit(&zfs_share_lock); 3193da6c28aaSamw return (ENOSYS); 3194da6c28aaSamw } 3195da6c28aaSamw zfs_nfsshare_inited = 1; 3196ecd6cf80Smarks mutex_exit(&zfs_share_lock); 3197ecd6cf80Smarks } 3198da6c28aaSamw break; 3199da6c28aaSamw case ZFS_SHARE_SMB: 3200da6c28aaSamw case ZFS_UNSHARE_SMB: 3201da6c28aaSamw if (zfs_smbshare_inited == 0) { 3202da6c28aaSamw mutex_enter(&zfs_share_lock); 3203da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 3204da6c28aaSamw ddi_modopen("drv/smbsrv", 3205da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 3206da6c28aaSamw mutex_exit(&zfs_share_lock); 3207da6c28aaSamw return (ENOSYS); 3208da6c28aaSamw } 3209da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 3210da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 3211faa1795aSjb "smb_server_share", &error)) == NULL)) { 3212da6c28aaSamw mutex_exit(&zfs_share_lock); 3213da6c28aaSamw return (ENOSYS); 3214da6c28aaSamw } 3215da6c28aaSamw error = zfs_init_sharefs(); 3216da6c28aaSamw if (error) { 3217da6c28aaSamw mutex_exit(&zfs_share_lock); 3218da6c28aaSamw return (ENOSYS); 3219da6c28aaSamw } 3220da6c28aaSamw zfs_smbshare_inited = 1; 3221ecd6cf80Smarks mutex_exit(&zfs_share_lock); 3222ecd6cf80Smarks } 3223da6c28aaSamw break; 3224da6c28aaSamw default: 3225da6c28aaSamw return (EINVAL); 3226da6c28aaSamw } 3227ecd6cf80Smarks 3228da6c28aaSamw switch (zc->zc_share.z_sharetype) { 3229da6c28aaSamw case ZFS_SHARE_NFS: 3230da6c28aaSamw case ZFS_UNSHARE_NFS: 3231da6c28aaSamw if (error = 3232da6c28aaSamw znfsexport_fs((void *) 3233da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 3234da6c28aaSamw return (error); 3235da6c28aaSamw break; 3236da6c28aaSamw case ZFS_SHARE_SMB: 3237da6c28aaSamw case ZFS_UNSHARE_SMB: 3238da6c28aaSamw if (error = zsmbexport_fs((void *) 3239da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 3240da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 3241743a77edSAlan Wright B_TRUE: B_FALSE)) { 3242da6c28aaSamw return (error); 3243ecd6cf80Smarks } 3244da6c28aaSamw break; 3245ecd6cf80Smarks } 3246ecd6cf80Smarks 3247da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 3248da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 3249ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 3250ecd6cf80Smarks 3251da6c28aaSamw /* 3252da6c28aaSamw * Add or remove share from sharetab 3253da6c28aaSamw */ 3254ecd6cf80Smarks error = zshare_fs(opcode, 3255ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 3256ecd6cf80Smarks zc->zc_share.z_sharemax); 3257ecd6cf80Smarks 3258ecd6cf80Smarks return (error); 3259ecd6cf80Smarks 3260ecd6cf80Smarks } 3261ecd6cf80Smarks 3262743a77edSAlan Wright ace_t full_access[] = { 3263743a77edSAlan Wright {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 3264743a77edSAlan Wright }; 3265743a77edSAlan Wright 3266743a77edSAlan Wright /* 3267743a77edSAlan Wright * Remove all ACL files in shares dir 3268743a77edSAlan Wright */ 3269743a77edSAlan Wright static int 3270743a77edSAlan Wright zfs_smb_acl_purge(znode_t *dzp) 3271743a77edSAlan Wright { 3272743a77edSAlan Wright zap_cursor_t zc; 3273743a77edSAlan Wright zap_attribute_t zap; 3274743a77edSAlan Wright zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 3275743a77edSAlan Wright int error; 3276743a77edSAlan Wright 3277743a77edSAlan Wright for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 3278743a77edSAlan Wright (error = zap_cursor_retrieve(&zc, &zap)) == 0; 3279743a77edSAlan Wright zap_cursor_advance(&zc)) { 3280743a77edSAlan Wright if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 3281743a77edSAlan Wright NULL, 0)) != 0) 3282743a77edSAlan Wright break; 3283743a77edSAlan Wright } 3284743a77edSAlan Wright zap_cursor_fini(&zc); 3285743a77edSAlan Wright return (error); 3286743a77edSAlan Wright } 3287743a77edSAlan Wright 3288743a77edSAlan Wright static int 3289743a77edSAlan Wright zfs_ioc_smb_acl(zfs_cmd_t *zc) 3290743a77edSAlan Wright { 3291743a77edSAlan Wright vnode_t *vp; 3292743a77edSAlan Wright znode_t *dzp; 3293743a77edSAlan Wright vnode_t *resourcevp = NULL; 3294743a77edSAlan Wright znode_t *sharedir; 3295743a77edSAlan Wright zfsvfs_t *zfsvfs; 3296743a77edSAlan Wright nvlist_t *nvlist; 3297743a77edSAlan Wright char *src, *target; 3298743a77edSAlan Wright vattr_t vattr; 3299743a77edSAlan Wright vsecattr_t vsec; 3300743a77edSAlan Wright int error = 0; 3301743a77edSAlan Wright 3302743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 3303743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 3304743a77edSAlan Wright return (error); 3305743a77edSAlan Wright 3306743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 3307743a77edSAlan Wright 3308743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 3309743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 3310743a77edSAlan Wright zc->zc_name) != 0)) { 3311743a77edSAlan Wright VN_RELE(vp); 3312743a77edSAlan Wright return (EINVAL); 3313743a77edSAlan Wright } 3314743a77edSAlan Wright 3315743a77edSAlan Wright dzp = VTOZ(vp); 3316743a77edSAlan Wright zfsvfs = dzp->z_zfsvfs; 3317743a77edSAlan Wright ZFS_ENTER(zfsvfs); 3318743a77edSAlan Wright 33199e1320c0SMark Shellenbaum /* 33209e1320c0SMark Shellenbaum * Create share dir if its missing. 33219e1320c0SMark Shellenbaum */ 33229e1320c0SMark Shellenbaum mutex_enter(&zfsvfs->z_lock); 33239e1320c0SMark Shellenbaum if (zfsvfs->z_shares_dir == 0) { 33249e1320c0SMark Shellenbaum dmu_tx_t *tx; 33259e1320c0SMark Shellenbaum 33269e1320c0SMark Shellenbaum tx = dmu_tx_create(zfsvfs->z_os); 33279e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 33289e1320c0SMark Shellenbaum ZFS_SHARES_DIR); 33299e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 33309e1320c0SMark Shellenbaum error = dmu_tx_assign(tx, TXG_WAIT); 33319e1320c0SMark Shellenbaum if (error) { 33329e1320c0SMark Shellenbaum dmu_tx_abort(tx); 33339e1320c0SMark Shellenbaum } else { 33349e1320c0SMark Shellenbaum error = zfs_create_share_dir(zfsvfs, tx); 33359e1320c0SMark Shellenbaum dmu_tx_commit(tx); 33369e1320c0SMark Shellenbaum } 33379e1320c0SMark Shellenbaum if (error) { 33389e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 33399e1320c0SMark Shellenbaum VN_RELE(vp); 33409e1320c0SMark Shellenbaum ZFS_EXIT(zfsvfs); 33419e1320c0SMark Shellenbaum return (error); 33429e1320c0SMark Shellenbaum } 33439e1320c0SMark Shellenbaum } 33449e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 33459e1320c0SMark Shellenbaum 33469e1320c0SMark Shellenbaum ASSERT(zfsvfs->z_shares_dir); 3347743a77edSAlan Wright if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 33489e1320c0SMark Shellenbaum VN_RELE(vp); 3349743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3350743a77edSAlan Wright return (error); 3351743a77edSAlan Wright } 3352743a77edSAlan Wright 3353743a77edSAlan Wright switch (zc->zc_cookie) { 3354743a77edSAlan Wright case ZFS_SMB_ACL_ADD: 3355743a77edSAlan Wright vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 3356743a77edSAlan Wright vattr.va_type = VREG; 3357743a77edSAlan Wright vattr.va_mode = S_IFREG|0777; 3358743a77edSAlan Wright vattr.va_uid = 0; 3359743a77edSAlan Wright vattr.va_gid = 0; 3360743a77edSAlan Wright 3361743a77edSAlan Wright vsec.vsa_mask = VSA_ACE; 3362743a77edSAlan Wright vsec.vsa_aclentp = &full_access; 3363743a77edSAlan Wright vsec.vsa_aclentsz = sizeof (full_access); 3364743a77edSAlan Wright vsec.vsa_aclcnt = 1; 3365743a77edSAlan Wright 3366743a77edSAlan Wright error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 3367743a77edSAlan Wright &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 3368743a77edSAlan Wright if (resourcevp) 3369743a77edSAlan Wright VN_RELE(resourcevp); 3370743a77edSAlan Wright break; 3371743a77edSAlan Wright 3372743a77edSAlan Wright case ZFS_SMB_ACL_REMOVE: 3373743a77edSAlan Wright error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 3374743a77edSAlan Wright NULL, 0); 3375743a77edSAlan Wright break; 3376743a77edSAlan Wright 3377743a77edSAlan Wright case ZFS_SMB_ACL_RENAME: 3378743a77edSAlan Wright if ((error = get_nvlist(zc->zc_nvlist_src, 3379743a77edSAlan Wright zc->zc_nvlist_src_size, &nvlist)) != 0) { 3380743a77edSAlan Wright VN_RELE(vp); 3381743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3382743a77edSAlan Wright return (error); 3383743a77edSAlan Wright } 3384743a77edSAlan Wright if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 3385743a77edSAlan Wright nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 3386743a77edSAlan Wright &target)) { 3387743a77edSAlan Wright VN_RELE(vp); 338889459e17SMark Shellenbaum VN_RELE(ZTOV(sharedir)); 3389743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3390743a77edSAlan Wright return (error); 3391743a77edSAlan Wright } 3392743a77edSAlan Wright error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 3393743a77edSAlan Wright kcred, NULL, 0); 3394743a77edSAlan Wright nvlist_free(nvlist); 3395743a77edSAlan Wright break; 3396743a77edSAlan Wright 3397743a77edSAlan Wright case ZFS_SMB_ACL_PURGE: 3398743a77edSAlan Wright error = zfs_smb_acl_purge(sharedir); 3399743a77edSAlan Wright break; 3400743a77edSAlan Wright 3401743a77edSAlan Wright default: 3402743a77edSAlan Wright error = EINVAL; 3403743a77edSAlan Wright break; 3404743a77edSAlan Wright } 3405743a77edSAlan Wright 3406743a77edSAlan Wright VN_RELE(vp); 3407743a77edSAlan Wright VN_RELE(ZTOV(sharedir)); 3408743a77edSAlan Wright 3409743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3410743a77edSAlan Wright 3411743a77edSAlan Wright return (error); 3412743a77edSAlan Wright } 3413743a77edSAlan Wright 3414ecd6cf80Smarks /* 34152a6b87f0Sek * pool create, destroy, and export don't log the history as part of 34162a6b87f0Sek * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 34172a6b87f0Sek * do the logging of those commands. 3418ecd6cf80Smarks */ 3419fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 342054d692b7SGeorge Wilson { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE, 342154d692b7SGeorge Wilson B_FALSE }, 342254d692b7SGeorge Wilson { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE, 342354d692b7SGeorge Wilson B_FALSE }, 342454d692b7SGeorge Wilson { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE, 342554d692b7SGeorge Wilson B_FALSE }, 342654d692b7SGeorge Wilson { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE, 342754d692b7SGeorge Wilson B_FALSE }, 342854d692b7SGeorge Wilson { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE, 342954d692b7SGeorge Wilson B_FALSE }, 343054d692b7SGeorge Wilson { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE, 343154d692b7SGeorge Wilson B_FALSE }, 343254d692b7SGeorge Wilson { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE, 343354d692b7SGeorge Wilson B_FALSE }, 343454d692b7SGeorge Wilson { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE, 343554d692b7SGeorge Wilson B_TRUE }, 343654d692b7SGeorge Wilson { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, 343754d692b7SGeorge Wilson B_FALSE }, 343854d692b7SGeorge Wilson { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE, 343954d692b7SGeorge Wilson B_TRUE }, 344054d692b7SGeorge Wilson { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE, 344154d692b7SGeorge Wilson B_FALSE }, 344254d692b7SGeorge Wilson { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE, 344354d692b7SGeorge Wilson B_TRUE }, 344454d692b7SGeorge Wilson { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE, 344554d692b7SGeorge Wilson B_TRUE }, 344654d692b7SGeorge Wilson { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE, 344754d692b7SGeorge Wilson B_FALSE }, 344854d692b7SGeorge Wilson { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 344954d692b7SGeorge Wilson B_TRUE }, 345054d692b7SGeorge Wilson { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 345154d692b7SGeorge Wilson B_TRUE }, 345254d692b7SGeorge Wilson { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE, 345354d692b7SGeorge Wilson B_TRUE }, 345454d692b7SGeorge Wilson { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 345554d692b7SGeorge Wilson B_FALSE }, 345654d692b7SGeorge Wilson { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 345754d692b7SGeorge Wilson B_FALSE }, 345854d692b7SGeorge Wilson { zfs_ioc_dataset_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 345954d692b7SGeorge Wilson B_FALSE }, 346054d692b7SGeorge Wilson { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 346154d692b7SGeorge Wilson B_FALSE }, 346254d692b7SGeorge Wilson { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, B_TRUE }, 346354d692b7SGeorge Wilson { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE, 346454d692b7SGeorge Wilson B_FALSE }, 346554d692b7SGeorge Wilson { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE, 346654d692b7SGeorge Wilson B_FALSE }, 346754d692b7SGeorge Wilson { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, B_TRUE }, 346854d692b7SGeorge Wilson { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 346954d692b7SGeorge Wilson B_TRUE}, 347054d692b7SGeorge Wilson { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE, 347154d692b7SGeorge Wilson B_TRUE }, 347254d692b7SGeorge Wilson { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE, B_TRUE }, 347354d692b7SGeorge Wilson { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE, B_TRUE }, 347454d692b7SGeorge Wilson { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE, B_FALSE }, 347554d692b7SGeorge Wilson { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 347654d692b7SGeorge Wilson B_FALSE }, 347754d692b7SGeorge Wilson { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 347854d692b7SGeorge Wilson B_FALSE }, 347954d692b7SGeorge Wilson { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE, 348054d692b7SGeorge Wilson B_FALSE }, 348154d692b7SGeorge Wilson { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE, 348254d692b7SGeorge Wilson B_FALSE }, 348354d692b7SGeorge Wilson { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE, B_FALSE }, 348454d692b7SGeorge Wilson { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE, 348554d692b7SGeorge Wilson B_TRUE }, 348654d692b7SGeorge Wilson { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 348754d692b7SGeorge Wilson B_TRUE }, 348854d692b7SGeorge Wilson { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE, 348954d692b7SGeorge Wilson B_TRUE }, 349054d692b7SGeorge Wilson { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE, 349154d692b7SGeorge Wilson B_FALSE }, 349254d692b7SGeorge Wilson { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE, 349354d692b7SGeorge Wilson B_FALSE }, 349454d692b7SGeorge Wilson { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE, 349554d692b7SGeorge Wilson B_TRUE }, 349654d692b7SGeorge Wilson { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE, 349754d692b7SGeorge Wilson B_FALSE }, 349854d692b7SGeorge Wilson { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE, 349954d692b7SGeorge Wilson B_TRUE }, 350054d692b7SGeorge Wilson { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 350154d692b7SGeorge Wilson B_FALSE }, 350254d692b7SGeorge Wilson { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, DATASET_NAME, B_FALSE, 350354d692b7SGeorge Wilson B_FALSE }, 350454d692b7SGeorge Wilson { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE, B_FALSE }, 350554d692b7SGeorge Wilson { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE, 350654d692b7SGeorge Wilson B_TRUE }, 350754d692b7SGeorge Wilson { zfs_ioc_smb_acl, zfs_secpolicy_smb_acl, DATASET_NAME, B_FALSE, 3508*14843421SMatthew Ahrens B_FALSE }, 3509*14843421SMatthew Ahrens { zfs_ioc_userspace_one, zfs_secpolicy_userspace_one, 3510*14843421SMatthew Ahrens DATASET_NAME, B_FALSE, B_FALSE }, 3511*14843421SMatthew Ahrens { zfs_ioc_userspace_many, zfs_secpolicy_userspace_many, 3512*14843421SMatthew Ahrens DATASET_NAME, B_FALSE, B_FALSE }, 3513*14843421SMatthew Ahrens { zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 3514*14843421SMatthew Ahrens DATASET_NAME, B_FALSE, B_TRUE }, 3515fa9e4066Sahrens }; 3516fa9e4066Sahrens 351754d692b7SGeorge Wilson int 351854d692b7SGeorge Wilson pool_status_check(const char *name, zfs_ioc_namecheck_t type) 351954d692b7SGeorge Wilson { 352054d692b7SGeorge Wilson spa_t *spa; 352154d692b7SGeorge Wilson int error; 352254d692b7SGeorge Wilson 352354d692b7SGeorge Wilson ASSERT(type == POOL_NAME || type == DATASET_NAME); 352454d692b7SGeorge Wilson 3525*14843421SMatthew Ahrens error = spa_open(name, &spa, FTAG); 352654d692b7SGeorge Wilson if (error == 0) { 352754d692b7SGeorge Wilson if (spa_suspended(spa)) 352854d692b7SGeorge Wilson error = EAGAIN; 352954d692b7SGeorge Wilson spa_close(spa, FTAG); 353054d692b7SGeorge Wilson } 353154d692b7SGeorge Wilson return (error); 353254d692b7SGeorge Wilson } 353354d692b7SGeorge Wilson 3534fa9e4066Sahrens static int 3535fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 3536fa9e4066Sahrens { 3537fa9e4066Sahrens zfs_cmd_t *zc; 3538fa9e4066Sahrens uint_t vec; 35391d452cf5Sahrens int error, rc; 3540fa9e4066Sahrens 3541fa9e4066Sahrens if (getminor(dev) != 0) 3542fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 3543fa9e4066Sahrens 3544fa9e4066Sahrens vec = cmd - ZFS_IOC; 354591ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 3546fa9e4066Sahrens 3547fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 3548fa9e4066Sahrens return (EINVAL); 3549fa9e4066Sahrens 3550fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 3551fa9e4066Sahrens 3552fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 3553fa9e4066Sahrens 355491ebeef5Sahrens if (error == 0) 3555ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 3556fa9e4066Sahrens 3557fa9e4066Sahrens /* 3558fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 3559fa9e4066Sahrens * the lower layers. 3560fa9e4066Sahrens */ 3561fa9e4066Sahrens if (error == 0) { 3562fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 3563fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 3564e7437265Sahrens case POOL_NAME: 3565fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 3566fa9e4066Sahrens error = EINVAL; 356754d692b7SGeorge Wilson if (zfs_ioc_vec[vec].zvec_pool_check) 356854d692b7SGeorge Wilson error = pool_status_check(zc->zc_name, 356954d692b7SGeorge Wilson zfs_ioc_vec[vec].zvec_namecheck); 3570fa9e4066Sahrens break; 3571fa9e4066Sahrens 3572e7437265Sahrens case DATASET_NAME: 3573fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 3574fa9e4066Sahrens error = EINVAL; 357554d692b7SGeorge Wilson if (zfs_ioc_vec[vec].zvec_pool_check) 357654d692b7SGeorge Wilson error = pool_status_check(zc->zc_name, 357754d692b7SGeorge Wilson zfs_ioc_vec[vec].zvec_namecheck); 3578fa9e4066Sahrens break; 35795ad82045Snd 3580e7437265Sahrens case NO_NAME: 35815ad82045Snd break; 3582fa9e4066Sahrens } 3583fa9e4066Sahrens } 3584fa9e4066Sahrens 3585fa9e4066Sahrens if (error == 0) 3586fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 3587fa9e4066Sahrens 35881d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 3589ecd6cf80Smarks if (error == 0) { 35901d452cf5Sahrens error = rc; 3591*14843421SMatthew Ahrens if (zfs_ioc_vec[vec].zvec_his_log) 3592ecd6cf80Smarks zfs_log_history(zc); 3593ecd6cf80Smarks } 3594fa9e4066Sahrens 3595fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 3596fa9e4066Sahrens return (error); 3597fa9e4066Sahrens } 3598fa9e4066Sahrens 3599fa9e4066Sahrens static int 3600fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3601fa9e4066Sahrens { 3602fa9e4066Sahrens if (cmd != DDI_ATTACH) 3603fa9e4066Sahrens return (DDI_FAILURE); 3604fa9e4066Sahrens 3605fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 3606fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 3607fa9e4066Sahrens return (DDI_FAILURE); 3608fa9e4066Sahrens 3609fa9e4066Sahrens zfs_dip = dip; 3610fa9e4066Sahrens 3611fa9e4066Sahrens ddi_report_dev(dip); 3612fa9e4066Sahrens 3613fa9e4066Sahrens return (DDI_SUCCESS); 3614fa9e4066Sahrens } 3615fa9e4066Sahrens 3616fa9e4066Sahrens static int 3617fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3618fa9e4066Sahrens { 3619fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 3620fa9e4066Sahrens return (DDI_FAILURE); 3621fa9e4066Sahrens 3622fa9e4066Sahrens if (cmd != DDI_DETACH) 3623fa9e4066Sahrens return (DDI_FAILURE); 3624fa9e4066Sahrens 3625fa9e4066Sahrens zfs_dip = NULL; 3626fa9e4066Sahrens 3627fa9e4066Sahrens ddi_prop_remove_all(dip); 3628fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 3629fa9e4066Sahrens 3630fa9e4066Sahrens return (DDI_SUCCESS); 3631fa9e4066Sahrens } 3632fa9e4066Sahrens 3633fa9e4066Sahrens /*ARGSUSED*/ 3634fa9e4066Sahrens static int 3635fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3636fa9e4066Sahrens { 3637fa9e4066Sahrens switch (infocmd) { 3638fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 3639fa9e4066Sahrens *result = zfs_dip; 3640fa9e4066Sahrens return (DDI_SUCCESS); 3641fa9e4066Sahrens 3642fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 3643a0965f35Sbonwick *result = (void *)0; 3644fa9e4066Sahrens return (DDI_SUCCESS); 3645fa9e4066Sahrens } 3646fa9e4066Sahrens 3647fa9e4066Sahrens return (DDI_FAILURE); 3648fa9e4066Sahrens } 3649fa9e4066Sahrens 3650fa9e4066Sahrens /* 3651fa9e4066Sahrens * OK, so this is a little weird. 3652fa9e4066Sahrens * 3653fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 3654fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3655fa9e4066Sahrens * 3656fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 3657fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 3658fa9e4066Sahrens */ 3659fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 3660fa9e4066Sahrens zvol_open, /* open */ 3661fa9e4066Sahrens zvol_close, /* close */ 3662fa9e4066Sahrens zvol_strategy, /* strategy */ 3663fa9e4066Sahrens nodev, /* print */ 3664e7cbe64fSgw zvol_dump, /* dump */ 3665fa9e4066Sahrens zvol_read, /* read */ 3666fa9e4066Sahrens zvol_write, /* write */ 3667fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 3668fa9e4066Sahrens nodev, /* devmap */ 3669fa9e4066Sahrens nodev, /* mmap */ 3670fa9e4066Sahrens nodev, /* segmap */ 3671fa9e4066Sahrens nochpoll, /* poll */ 3672fa9e4066Sahrens ddi_prop_op, /* prop_op */ 3673fa9e4066Sahrens NULL, /* streamtab */ 3674fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 3675fa9e4066Sahrens CB_REV, /* version */ 3676feb08c6bSbillm nodev, /* async read */ 3677feb08c6bSbillm nodev, /* async write */ 3678fa9e4066Sahrens }; 3679fa9e4066Sahrens 3680fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 3681fa9e4066Sahrens DEVO_REV, /* version */ 3682fa9e4066Sahrens 0, /* refcnt */ 3683fa9e4066Sahrens zfs_info, /* info */ 3684fa9e4066Sahrens nulldev, /* identify */ 3685fa9e4066Sahrens nulldev, /* probe */ 3686fa9e4066Sahrens zfs_attach, /* attach */ 3687fa9e4066Sahrens zfs_detach, /* detach */ 3688fa9e4066Sahrens nodev, /* reset */ 3689fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 369019397407SSherry Moore NULL, /* no bus operations */ 369119397407SSherry Moore NULL, /* power */ 369219397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 3693fa9e4066Sahrens }; 3694fa9e4066Sahrens 3695fa9e4066Sahrens static struct modldrv zfs_modldrv = { 369619397407SSherry Moore &mod_driverops, 369719397407SSherry Moore "ZFS storage pool", 369819397407SSherry Moore &zfs_dev_ops 3699fa9e4066Sahrens }; 3700fa9e4066Sahrens 3701fa9e4066Sahrens static struct modlinkage modlinkage = { 3702fa9e4066Sahrens MODREV_1, 3703fa9e4066Sahrens (void *)&zfs_modlfs, 3704fa9e4066Sahrens (void *)&zfs_modldrv, 3705fa9e4066Sahrens NULL 3706fa9e4066Sahrens }; 3707fa9e4066Sahrens 3708ec533521Sfr 3709ec533521Sfr uint_t zfs_fsyncer_key; 3710f18faf3fSek extern uint_t rrw_tsd_key; 3711ec533521Sfr 3712fa9e4066Sahrens int 3713fa9e4066Sahrens _init(void) 3714fa9e4066Sahrens { 3715fa9e4066Sahrens int error; 3716fa9e4066Sahrens 3717a0965f35Sbonwick spa_init(FREAD | FWRITE); 3718a0965f35Sbonwick zfs_init(); 3719a0965f35Sbonwick zvol_init(); 3720a0965f35Sbonwick 3721a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 3722a0965f35Sbonwick zvol_fini(); 3723a0965f35Sbonwick zfs_fini(); 3724a0965f35Sbonwick spa_fini(); 3725fa9e4066Sahrens return (error); 3726a0965f35Sbonwick } 3727fa9e4066Sahrens 3728ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 3729f18faf3fSek tsd_create(&rrw_tsd_key, NULL); 3730ec533521Sfr 3731fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 3732fa9e4066Sahrens ASSERT(error == 0); 3733ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3734fa9e4066Sahrens 3735fa9e4066Sahrens return (0); 3736fa9e4066Sahrens } 3737fa9e4066Sahrens 3738fa9e4066Sahrens int 3739fa9e4066Sahrens _fini(void) 3740fa9e4066Sahrens { 3741fa9e4066Sahrens int error; 3742fa9e4066Sahrens 3743ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3744fa9e4066Sahrens return (EBUSY); 3745fa9e4066Sahrens 3746fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3747fa9e4066Sahrens return (error); 3748fa9e4066Sahrens 3749fa9e4066Sahrens zvol_fini(); 3750fa9e4066Sahrens zfs_fini(); 3751fa9e4066Sahrens spa_fini(); 3752da6c28aaSamw if (zfs_nfsshare_inited) 3753ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 3754da6c28aaSamw if (zfs_smbshare_inited) 3755da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 3756da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 3757ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 3758fa9e4066Sahrens 3759ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 3760fa9e4066Sahrens ldi_ident_release(zfs_li); 3761fa9e4066Sahrens zfs_li = NULL; 3762ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 3763fa9e4066Sahrens 3764fa9e4066Sahrens return (error); 3765fa9e4066Sahrens } 3766fa9e4066Sahrens 3767fa9e4066Sahrens int 3768fa9e4066Sahrens _info(struct modinfo *modinfop) 3769fa9e4066Sahrens { 3770fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 3771fa9e4066Sahrens } 3772