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 /* 22*9e6eda55Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/types.h> 29fa9e4066Sahrens #include <sys/param.h> 30fa9e4066Sahrens #include <sys/errno.h> 31fa9e4066Sahrens #include <sys/uio.h> 32fa9e4066Sahrens #include <sys/buf.h> 33fa9e4066Sahrens #include <sys/modctl.h> 34fa9e4066Sahrens #include <sys/open.h> 35fa9e4066Sahrens #include <sys/file.h> 36fa9e4066Sahrens #include <sys/kmem.h> 37fa9e4066Sahrens #include <sys/conf.h> 38fa9e4066Sahrens #include <sys/cmn_err.h> 39fa9e4066Sahrens #include <sys/stat.h> 40fa9e4066Sahrens #include <sys/zfs_ioctl.h> 41da6c28aaSamw #include <sys/zfs_znode.h> 42fa9e4066Sahrens #include <sys/zap.h> 43fa9e4066Sahrens #include <sys/spa.h> 44b1b8ab34Slling #include <sys/spa_impl.h> 45fa9e4066Sahrens #include <sys/vdev.h> 46b1b8ab34Slling #include <sys/vdev_impl.h> 47fa9e4066Sahrens #include <sys/dmu.h> 48fa9e4066Sahrens #include <sys/dsl_dir.h> 49fa9e4066Sahrens #include <sys/dsl_dataset.h> 50fa9e4066Sahrens #include <sys/dsl_prop.h> 51ecd6cf80Smarks #include <sys/dsl_deleg.h> 52ecd6cf80Smarks #include <sys/dmu_objset.h> 53fa9e4066Sahrens #include <sys/ddi.h> 54fa9e4066Sahrens #include <sys/sunddi.h> 55fa9e4066Sahrens #include <sys/sunldi.h> 56fa9e4066Sahrens #include <sys/policy.h> 57fa9e4066Sahrens #include <sys/zone.h> 58fa9e4066Sahrens #include <sys/nvpair.h> 59fa9e4066Sahrens #include <sys/pathname.h> 60fa9e4066Sahrens #include <sys/mount.h> 61fa9e4066Sahrens #include <sys/sdt.h> 62fa9e4066Sahrens #include <sys/fs/zfs.h> 63fa9e4066Sahrens #include <sys/zfs_ctldir.h> 64da6c28aaSamw #include <sys/zfs_dir.h> 65a2eea2e1Sahrens #include <sys/zvol.h> 66ecd6cf80Smarks #include <sharefs/share.h> 67f18faf3fSek #include <sys/dmu_objset.h> 68fa9e4066Sahrens 69fa9e4066Sahrens #include "zfs_namecheck.h" 70e9dbad6fSeschrock #include "zfs_prop.h" 71ecd6cf80Smarks #include "zfs_deleg.h" 72fa9e4066Sahrens 73fa9e4066Sahrens extern struct modlfs zfs_modlfs; 74fa9e4066Sahrens 75fa9e4066Sahrens extern void zfs_init(void); 76fa9e4066Sahrens extern void zfs_fini(void); 77fa9e4066Sahrens 78fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 79fa9e4066Sahrens dev_info_t *zfs_dip; 80fa9e4066Sahrens 81fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 82ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 83fa9e4066Sahrens 84fa9e4066Sahrens typedef struct zfs_ioc_vec { 85fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 86fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 87fa9e4066Sahrens enum { 88e7437265Sahrens NO_NAME, 89e7437265Sahrens POOL_NAME, 90e7437265Sahrens DATASET_NAME 91ecd6cf80Smarks } zvec_namecheck; 92ecd6cf80Smarks boolean_t zvec_his_log; 93fa9e4066Sahrens } zfs_ioc_vec_t; 94fa9e4066Sahrens 95fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 96fa9e4066Sahrens void 97fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 98fa9e4066Sahrens { 99fa9e4066Sahrens const char *newfile; 100fa9e4066Sahrens char buf[256]; 101fa9e4066Sahrens va_list adx; 102fa9e4066Sahrens 103fa9e4066Sahrens /* 104fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 105fa9e4066Sahrens */ 106fa9e4066Sahrens newfile = strrchr(file, '/'); 107fa9e4066Sahrens if (newfile != NULL) { 108fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 109fa9e4066Sahrens } else { 110fa9e4066Sahrens newfile = file; 111fa9e4066Sahrens } 112fa9e4066Sahrens 113fa9e4066Sahrens va_start(adx, fmt); 114fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 115fa9e4066Sahrens va_end(adx); 116fa9e4066Sahrens 117fa9e4066Sahrens /* 118fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 119fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 120fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 121fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 122fa9e4066Sahrens * arg0 = file name 123fa9e4066Sahrens * arg1 = function name 124fa9e4066Sahrens * arg2 = line number 125fa9e4066Sahrens * arg3 = message 126fa9e4066Sahrens */ 127fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 128fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 129fa9e4066Sahrens } 130fa9e4066Sahrens 131ecd6cf80Smarks static void 132228975ccSek history_str_free(char *buf) 133228975ccSek { 134228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 135228975ccSek } 136228975ccSek 137228975ccSek static char * 138228975ccSek history_str_get(zfs_cmd_t *zc) 139ecd6cf80Smarks { 14040feaa91Sahrens char *buf; 141ecd6cf80Smarks 142ecd6cf80Smarks if (zc->zc_history == NULL) 143228975ccSek return (NULL); 144e7437265Sahrens 145ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 146ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 147ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 148228975ccSek history_str_free(buf); 149228975ccSek return (NULL); 150ecd6cf80Smarks } 151ecd6cf80Smarks 152ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 153ecd6cf80Smarks 154228975ccSek return (buf); 155228975ccSek } 156ecd6cf80Smarks 157c2a93d44Stimh /* 158c2a93d44Stimh * zfs_check_version 159c2a93d44Stimh * 160c2a93d44Stimh * Return non-zero if the spa version is less than requested version. 161c2a93d44Stimh */ 162da6c28aaSamw static int 163da6c28aaSamw zfs_check_version(const char *name, int version) 164da6c28aaSamw { 165da6c28aaSamw 166da6c28aaSamw spa_t *spa; 167da6c28aaSamw 168da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 169da6c28aaSamw if (spa_version(spa) < version) { 170da6c28aaSamw spa_close(spa, FTAG); 171da6c28aaSamw return (1); 172da6c28aaSamw } 173da6c28aaSamw spa_close(spa, FTAG); 174da6c28aaSamw } 175da6c28aaSamw return (0); 176da6c28aaSamw } 177da6c28aaSamw 178*9e6eda55Smarks /* 179*9e6eda55Smarks * zpl_check_version 180*9e6eda55Smarks * 181*9e6eda55Smarks * Return non-zero if the ZPL version is less than requested version. 182*9e6eda55Smarks */ 183*9e6eda55Smarks static int 184*9e6eda55Smarks zpl_check_version(const char *name, int version) 185*9e6eda55Smarks { 186*9e6eda55Smarks objset_t *os; 187*9e6eda55Smarks int rc = 1; 188*9e6eda55Smarks 189*9e6eda55Smarks if (dmu_objset_open(name, DMU_OST_ANY, 190*9e6eda55Smarks DS_MODE_STANDARD | DS_MODE_READONLY, &os) == 0) { 191*9e6eda55Smarks uint64_t propversion; 192*9e6eda55Smarks 193*9e6eda55Smarks if (zfs_get_zplprop(os, ZFS_PROP_VERSION, 194*9e6eda55Smarks &propversion) == 0) { 195*9e6eda55Smarks rc = !(propversion >= version); 196*9e6eda55Smarks } 197*9e6eda55Smarks dmu_objset_close(os); 198*9e6eda55Smarks } 199*9e6eda55Smarks return (rc); 200*9e6eda55Smarks } 201*9e6eda55Smarks 202228975ccSek static void 203228975ccSek zfs_log_history(zfs_cmd_t *zc) 204228975ccSek { 205228975ccSek spa_t *spa; 206228975ccSek char *buf; 207ecd6cf80Smarks 208228975ccSek if ((buf = history_str_get(zc)) == NULL) 209228975ccSek return; 210228975ccSek 211228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 212228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 213228975ccSek (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 214228975ccSek spa_close(spa, FTAG); 215228975ccSek } 216228975ccSek history_str_free(buf); 217ecd6cf80Smarks } 218ecd6cf80Smarks 219fa9e4066Sahrens /* 220fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 221fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 222fa9e4066Sahrens */ 223fa9e4066Sahrens /* ARGSUSED */ 224fa9e4066Sahrens static int 225ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 226fa9e4066Sahrens { 227fa9e4066Sahrens return (0); 228fa9e4066Sahrens } 229fa9e4066Sahrens 230fa9e4066Sahrens /* 231fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 232fa9e4066Sahrens * no privileges, but must be visible in the local zone. 233fa9e4066Sahrens */ 234fa9e4066Sahrens /* ARGSUSED */ 235fa9e4066Sahrens static int 236ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 237fa9e4066Sahrens { 238fa9e4066Sahrens if (INGLOBALZONE(curproc) || 239ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 240fa9e4066Sahrens return (0); 241fa9e4066Sahrens 242fa9e4066Sahrens return (ENOENT); 243fa9e4066Sahrens } 244fa9e4066Sahrens 245fa9e4066Sahrens static int 246fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 247fa9e4066Sahrens { 248fa9e4066Sahrens uint64_t zoned; 249fa9e4066Sahrens int writable = 1; 250fa9e4066Sahrens 251fa9e4066Sahrens /* 252fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 253fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 254fa9e4066Sahrens */ 255fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 256fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 257fa9e4066Sahrens return (ENOENT); 258fa9e4066Sahrens 259fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 260fa9e4066Sahrens return (ENOENT); 261fa9e4066Sahrens 262fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 263fa9e4066Sahrens /* 264fa9e4066Sahrens * If the fs is zoned, only root can access it from the 265fa9e4066Sahrens * global zone. 266fa9e4066Sahrens */ 267fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 268fa9e4066Sahrens return (EPERM); 269fa9e4066Sahrens } else { 270fa9e4066Sahrens /* 271fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 272fa9e4066Sahrens */ 273fa9e4066Sahrens if (!zoned) 274fa9e4066Sahrens return (EPERM); 275fa9e4066Sahrens 276fa9e4066Sahrens /* must be writable by this zone */ 277fa9e4066Sahrens if (!writable) 278fa9e4066Sahrens return (EPERM); 279fa9e4066Sahrens } 280fa9e4066Sahrens return (0); 281fa9e4066Sahrens } 282fa9e4066Sahrens 283fa9e4066Sahrens int 284ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 285fa9e4066Sahrens { 286fa9e4066Sahrens int error; 287fa9e4066Sahrens 288ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 289ecd6cf80Smarks if (error == 0) { 290ecd6cf80Smarks error = secpolicy_zfs(cr); 291db870a07Sahrens if (error) 292ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 293ecd6cf80Smarks } 294ecd6cf80Smarks return (error); 295ecd6cf80Smarks } 296ecd6cf80Smarks 297ecd6cf80Smarks static int 298ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 299ecd6cf80Smarks { 300ecd6cf80Smarks /* 301ecd6cf80Smarks * Check permissions for special properties. 302ecd6cf80Smarks */ 303ecd6cf80Smarks switch (prop) { 304ecd6cf80Smarks case ZFS_PROP_ZONED: 305ecd6cf80Smarks /* 306ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 307ecd6cf80Smarks */ 308ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 309ecd6cf80Smarks return (EPERM); 310ecd6cf80Smarks break; 311ecd6cf80Smarks 312ecd6cf80Smarks case ZFS_PROP_QUOTA: 313ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 314ecd6cf80Smarks uint64_t zoned; 315ecd6cf80Smarks char setpoint[MAXNAMELEN]; 316ecd6cf80Smarks /* 317ecd6cf80Smarks * Unprivileged users are allowed to modify the 318ecd6cf80Smarks * quota on things *under* (ie. contained by) 319ecd6cf80Smarks * the thing they own. 320ecd6cf80Smarks */ 321ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 322ecd6cf80Smarks setpoint)) 323ecd6cf80Smarks return (EPERM); 324db870a07Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 325ecd6cf80Smarks return (EPERM); 326ecd6cf80Smarks } 327db870a07Sahrens break; 328ecd6cf80Smarks } 329ecd6cf80Smarks 33091ebeef5Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 331ecd6cf80Smarks } 332ecd6cf80Smarks 333ecd6cf80Smarks int 334ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 335ecd6cf80Smarks { 336ecd6cf80Smarks int error; 337ecd6cf80Smarks 338ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 339ecd6cf80Smarks if (error) 340fa9e4066Sahrens return (error); 341fa9e4066Sahrens 342ecd6cf80Smarks /* 343ecd6cf80Smarks * permission to set permissions will be evaluated later in 344ecd6cf80Smarks * dsl_deleg_can_allow() 345ecd6cf80Smarks */ 346ecd6cf80Smarks return (0); 347ecd6cf80Smarks } 348ecd6cf80Smarks 349ecd6cf80Smarks int 350ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 351ecd6cf80Smarks { 352ecd6cf80Smarks int error; 353ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 354ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 355ecd6cf80Smarks if (error == 0) 356ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 357ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 358ecd6cf80Smarks return (error); 359ecd6cf80Smarks } 360ecd6cf80Smarks 361ecd6cf80Smarks int 362ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 363ecd6cf80Smarks { 364ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 365ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 366ecd6cf80Smarks } 367ecd6cf80Smarks 368ecd6cf80Smarks int 369ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 370ecd6cf80Smarks { 371ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 372ecd6cf80Smarks return (EPERM); 373ecd6cf80Smarks 3743cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 375ecd6cf80Smarks return (0); 376ecd6cf80Smarks } else { 377ecd6cf80Smarks vnode_t *vp; 378ecd6cf80Smarks int error; 379ecd6cf80Smarks 380ecd6cf80Smarks if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 381ecd6cf80Smarks NO_FOLLOW, NULL, &vp)) != 0) 382ecd6cf80Smarks return (error); 383ecd6cf80Smarks 384ecd6cf80Smarks /* Now make sure mntpnt and dataset are ZFS */ 385ecd6cf80Smarks 386ecd6cf80Smarks if (vp->v_vfsp->vfs_fstype != zfsfstype || 387ecd6cf80Smarks (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 388ecd6cf80Smarks zc->zc_name) != 0)) { 389ecd6cf80Smarks VN_RELE(vp); 390ecd6cf80Smarks return (EPERM); 391ecd6cf80Smarks } 392ecd6cf80Smarks 393ecd6cf80Smarks VN_RELE(vp); 394ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 395ecd6cf80Smarks ZFS_DELEG_PERM_SHARE, cr)); 396ecd6cf80Smarks } 397fa9e4066Sahrens } 398fa9e4066Sahrens 399fa9e4066Sahrens static int 400ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 401fa9e4066Sahrens { 402fa9e4066Sahrens char *cp; 403fa9e4066Sahrens 404fa9e4066Sahrens /* 405fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 406fa9e4066Sahrens */ 407ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 408ecd6cf80Smarks cp = strrchr(parent, '@'); 409fa9e4066Sahrens if (cp != NULL) { 410fa9e4066Sahrens cp[0] = '\0'; 411fa9e4066Sahrens } else { 412ecd6cf80Smarks cp = strrchr(parent, '/'); 413fa9e4066Sahrens if (cp == NULL) 414fa9e4066Sahrens return (ENOENT); 415fa9e4066Sahrens cp[0] = '\0'; 416ecd6cf80Smarks } 417ecd6cf80Smarks 418ecd6cf80Smarks return (0); 419ecd6cf80Smarks } 420ecd6cf80Smarks 421ecd6cf80Smarks int 422ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 423ecd6cf80Smarks { 424ecd6cf80Smarks int error; 425ecd6cf80Smarks 426ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 427ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 428ecd6cf80Smarks return (error); 429ecd6cf80Smarks 430ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 431ecd6cf80Smarks } 432ecd6cf80Smarks 433ecd6cf80Smarks static int 434ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 435ecd6cf80Smarks { 436ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 437ecd6cf80Smarks } 438ecd6cf80Smarks 439ecd6cf80Smarks /* 440ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 441ecd6cf80Smarks */ 442ecd6cf80Smarks /* ARGSUSED */ 443ecd6cf80Smarks static int 444ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 445ecd6cf80Smarks { 446ecd6cf80Smarks return (secpolicy_zfs(cr)); 447ecd6cf80Smarks } 448ecd6cf80Smarks 449ecd6cf80Smarks int 450ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 451ecd6cf80Smarks { 452ecd6cf80Smarks char parentname[MAXNAMELEN]; 453ecd6cf80Smarks int error; 454ecd6cf80Smarks 455ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 456ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 457ecd6cf80Smarks return (error); 458ecd6cf80Smarks 459ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 460ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 461ecd6cf80Smarks return (error); 462ecd6cf80Smarks 463ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 464ecd6cf80Smarks sizeof (parentname))) != 0) 465ecd6cf80Smarks return (error); 466ecd6cf80Smarks 467ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 468ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 469ecd6cf80Smarks return (error); 470ecd6cf80Smarks 471ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 472ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 473ecd6cf80Smarks return (error); 474ecd6cf80Smarks 475ecd6cf80Smarks return (error); 476ecd6cf80Smarks } 477ecd6cf80Smarks 478ecd6cf80Smarks static int 479ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 480ecd6cf80Smarks { 481ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 482ecd6cf80Smarks } 483ecd6cf80Smarks 484ecd6cf80Smarks static int 485ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 486ecd6cf80Smarks { 487ecd6cf80Smarks char parentname[MAXNAMELEN]; 488ecd6cf80Smarks objset_t *clone; 489ecd6cf80Smarks int error; 490ecd6cf80Smarks 491ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 492ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 493ecd6cf80Smarks if (error) 494ecd6cf80Smarks return (error); 495ecd6cf80Smarks 496ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 497ecd6cf80Smarks DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 498ecd6cf80Smarks 499ecd6cf80Smarks if (error == 0) { 500ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 501ecd6cf80Smarks dsl_dir_t *dd; 502ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 503ecd6cf80Smarks 504ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 505ecd6cf80Smarks error = dsl_dataset_open_obj(dd->dd_pool, 5063cb34c60Sahrens dd->dd_phys->dd_origin_obj, NULL, 507ecd6cf80Smarks DS_MODE_NONE, FTAG, &pclone); 508ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 509ecd6cf80Smarks if (error) { 510ecd6cf80Smarks dmu_objset_close(clone); 511ecd6cf80Smarks return (error); 512ecd6cf80Smarks } 513ecd6cf80Smarks 514ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 515ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 516ecd6cf80Smarks 517ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 518ecd6cf80Smarks dmu_objset_close(clone); 519ecd6cf80Smarks dsl_dataset_close(pclone, DS_MODE_NONE, FTAG); 520ecd6cf80Smarks if (error == 0) 521ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 522ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 523ecd6cf80Smarks } 524ecd6cf80Smarks return (error); 525ecd6cf80Smarks } 526ecd6cf80Smarks 527ecd6cf80Smarks static int 528ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 529ecd6cf80Smarks { 530ecd6cf80Smarks int error; 531ecd6cf80Smarks 532ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 533ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 534ecd6cf80Smarks return (error); 535ecd6cf80Smarks 536ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 537ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 538ecd6cf80Smarks return (error); 539ecd6cf80Smarks 540ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 541ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 542ecd6cf80Smarks } 543ecd6cf80Smarks 544ecd6cf80Smarks int 545ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 546ecd6cf80Smarks { 547ecd6cf80Smarks int error; 548ecd6cf80Smarks 549ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 550ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 551ecd6cf80Smarks return (error); 552ecd6cf80Smarks 553ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 554ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 555ecd6cf80Smarks 556ecd6cf80Smarks return (error); 557ecd6cf80Smarks } 558ecd6cf80Smarks 559ecd6cf80Smarks static int 560ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 561ecd6cf80Smarks { 562ecd6cf80Smarks 563ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 564ecd6cf80Smarks } 565ecd6cf80Smarks 566ecd6cf80Smarks static int 567ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 568ecd6cf80Smarks { 569ecd6cf80Smarks char parentname[MAXNAMELEN]; 570ecd6cf80Smarks int error; 571ecd6cf80Smarks 572ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 573ecd6cf80Smarks sizeof (parentname))) != 0) 574ecd6cf80Smarks return (error); 575fa9e4066Sahrens 576ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 577ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 578ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 579ecd6cf80Smarks return (error); 580fa9e4066Sahrens } 581fa9e4066Sahrens 582ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 583ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 584ecd6cf80Smarks return (error); 585ecd6cf80Smarks 586ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 587ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 588ecd6cf80Smarks 589ecd6cf80Smarks return (error); 590ecd6cf80Smarks } 591ecd6cf80Smarks 592ecd6cf80Smarks static int 593ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 594ecd6cf80Smarks { 595ecd6cf80Smarks int error; 596ecd6cf80Smarks 597ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 598ecd6cf80Smarks if (error) { 599ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 600ecd6cf80Smarks } 601ecd6cf80Smarks return (error); 602fa9e4066Sahrens } 603fa9e4066Sahrens 604fa9e4066Sahrens /* 605fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 606fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 607fa9e4066Sahrens */ 608fa9e4066Sahrens /* ARGSUSED */ 609fa9e4066Sahrens static int 610ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 611fa9e4066Sahrens { 612fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 613fa9e4066Sahrens return (EPERM); 614fa9e4066Sahrens 615fa9e4066Sahrens return (0); 616fa9e4066Sahrens } 617fa9e4066Sahrens 618ecd6cf80Smarks /* 619ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 620ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 621ecd6cf80Smarks * the minor nodes. 622ecd6cf80Smarks */ 623ecd6cf80Smarks static int 624ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 625ecd6cf80Smarks { 626ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 627ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 628ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 629ecd6cf80Smarks } 630ecd6cf80Smarks 631ecd6cf80Smarks return (0); 632ecd6cf80Smarks } 633ecd6cf80Smarks 634ea8dc4b6Seschrock /* 635ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 636ea8dc4b6Seschrock */ 637ea8dc4b6Seschrock /* ARGSUSED */ 638ea8dc4b6Seschrock static int 639ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 640ea8dc4b6Seschrock { 641ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 642ea8dc4b6Seschrock } 643ea8dc4b6Seschrock 644e45ce728Sahrens static int 645e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 646e45ce728Sahrens { 647e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 648e45ce728Sahrens 649990b4856Slling if (prop == ZPROP_INVAL) { 650e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 651e45ce728Sahrens return (EINVAL); 652e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 653e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 654e45ce728Sahrens } else { 655e45ce728Sahrens if (!zfs_prop_inheritable(prop)) 656e45ce728Sahrens return (EINVAL); 657e45ce728Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 658e45ce728Sahrens } 659e45ce728Sahrens } 660e45ce728Sahrens 661fa9e4066Sahrens /* 662fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 663fa9e4066Sahrens */ 664fa9e4066Sahrens static int 665990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 666fa9e4066Sahrens { 667fa9e4066Sahrens char *packed; 668fa9e4066Sahrens int error; 669990b4856Slling nvlist_t *list = NULL; 670fa9e4066Sahrens 671fa9e4066Sahrens /* 672e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 673fa9e4066Sahrens */ 674990b4856Slling if (size == 0) 675fa9e4066Sahrens return (EINVAL); 676fa9e4066Sahrens 677fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 678fa9e4066Sahrens 679990b4856Slling if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 680fa9e4066Sahrens kmem_free(packed, size); 681fa9e4066Sahrens return (error); 682fa9e4066Sahrens } 683fa9e4066Sahrens 684990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 685fa9e4066Sahrens kmem_free(packed, size); 686fa9e4066Sahrens return (error); 687fa9e4066Sahrens } 688fa9e4066Sahrens 689fa9e4066Sahrens kmem_free(packed, size); 690fa9e4066Sahrens 691990b4856Slling *nvp = list; 692fa9e4066Sahrens return (0); 693fa9e4066Sahrens } 694fa9e4066Sahrens 695e9dbad6fSeschrock static int 696e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 697e9dbad6fSeschrock { 698e9dbad6fSeschrock char *packed = NULL; 699e9dbad6fSeschrock size_t size; 700e9dbad6fSeschrock int error; 701e9dbad6fSeschrock 702e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 703e9dbad6fSeschrock 704e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 705e9dbad6fSeschrock error = ENOMEM; 706e9dbad6fSeschrock } else { 707da165920Smarks packed = kmem_alloc(size, KM_SLEEP); 708e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 709e9dbad6fSeschrock KM_SLEEP) == 0); 710e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 711e9dbad6fSeschrock size); 712e9dbad6fSeschrock kmem_free(packed, size); 713e9dbad6fSeschrock } 714e9dbad6fSeschrock 715e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 716e9dbad6fSeschrock return (error); 717e9dbad6fSeschrock } 718e9dbad6fSeschrock 719fa9e4066Sahrens static int 720fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 721fa9e4066Sahrens { 722fa9e4066Sahrens int error; 723990b4856Slling nvlist_t *config, *props = NULL; 724228975ccSek char *buf; 725fa9e4066Sahrens 726990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 727990b4856Slling &config)) 728fa9e4066Sahrens return (error); 7292a6b87f0Sek 730990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 731990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 732990b4856Slling nvlist_free(config); 733990b4856Slling return (error); 734990b4856Slling } 735990b4856Slling 7362a6b87f0Sek buf = history_str_get(zc); 737fa9e4066Sahrens 738990b4856Slling error = spa_create(zc->zc_name, config, props, buf); 739fa9e4066Sahrens 7402a6b87f0Sek if (buf != NULL) 7412a6b87f0Sek history_str_free(buf); 742990b4856Slling 743fa9e4066Sahrens nvlist_free(config); 744fa9e4066Sahrens 745990b4856Slling if (props) 746990b4856Slling nvlist_free(props); 747990b4856Slling 748fa9e4066Sahrens return (error); 749fa9e4066Sahrens } 750fa9e4066Sahrens 751fa9e4066Sahrens static int 752fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 753fa9e4066Sahrens { 754ecd6cf80Smarks int error; 755ecd6cf80Smarks zfs_log_history(zc); 756ecd6cf80Smarks error = spa_destroy(zc->zc_name); 757ecd6cf80Smarks return (error); 758fa9e4066Sahrens } 759fa9e4066Sahrens 760fa9e4066Sahrens static int 761fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 762fa9e4066Sahrens { 763fa9e4066Sahrens int error; 764990b4856Slling nvlist_t *config, *props = NULL; 765fa9e4066Sahrens uint64_t guid; 766fa9e4066Sahrens 767990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 768990b4856Slling &config)) != 0) 769990b4856Slling return (error); 770990b4856Slling 771990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 772990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 773990b4856Slling nvlist_free(config); 774fa9e4066Sahrens return (error); 775990b4856Slling } 776fa9e4066Sahrens 777fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 778ea8dc4b6Seschrock guid != zc->zc_guid) 779fa9e4066Sahrens error = EINVAL; 780fa9e4066Sahrens else 781990b4856Slling error = spa_import(zc->zc_name, config, props); 782fa9e4066Sahrens 783fa9e4066Sahrens nvlist_free(config); 784fa9e4066Sahrens 785990b4856Slling if (props) 786990b4856Slling nvlist_free(props); 787990b4856Slling 788fa9e4066Sahrens return (error); 789fa9e4066Sahrens } 790fa9e4066Sahrens 791fa9e4066Sahrens static int 792fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 793fa9e4066Sahrens { 794ecd6cf80Smarks int error; 795ecd6cf80Smarks zfs_log_history(zc); 796ecd6cf80Smarks error = spa_export(zc->zc_name, NULL); 797ecd6cf80Smarks return (error); 798fa9e4066Sahrens } 799fa9e4066Sahrens 800fa9e4066Sahrens static int 801fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 802fa9e4066Sahrens { 803fa9e4066Sahrens nvlist_t *configs; 804fa9e4066Sahrens int error; 805fa9e4066Sahrens 806fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 807fa9e4066Sahrens return (EEXIST); 808fa9e4066Sahrens 809e9dbad6fSeschrock error = put_nvlist(zc, configs); 810fa9e4066Sahrens 811fa9e4066Sahrens nvlist_free(configs); 812fa9e4066Sahrens 813fa9e4066Sahrens return (error); 814fa9e4066Sahrens } 815fa9e4066Sahrens 816fa9e4066Sahrens static int 817fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 818fa9e4066Sahrens { 819fa9e4066Sahrens nvlist_t *config; 820fa9e4066Sahrens int error; 821ea8dc4b6Seschrock int ret = 0; 822fa9e4066Sahrens 823e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 824e9dbad6fSeschrock sizeof (zc->zc_value)); 825fa9e4066Sahrens 826fa9e4066Sahrens if (config != NULL) { 827e9dbad6fSeschrock ret = put_nvlist(zc, config); 828fa9e4066Sahrens nvlist_free(config); 829ea8dc4b6Seschrock 830ea8dc4b6Seschrock /* 831ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 832ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 833ea8dc4b6Seschrock * in 'zc_cookie'. 834ea8dc4b6Seschrock */ 835ea8dc4b6Seschrock zc->zc_cookie = error; 836fa9e4066Sahrens } else { 837ea8dc4b6Seschrock ret = error; 838fa9e4066Sahrens } 839fa9e4066Sahrens 840ea8dc4b6Seschrock return (ret); 841fa9e4066Sahrens } 842fa9e4066Sahrens 843fa9e4066Sahrens /* 844fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 845fa9e4066Sahrens * user land knows which devices are available and overall pool health. 846fa9e4066Sahrens */ 847fa9e4066Sahrens static int 848fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 849fa9e4066Sahrens { 850fa9e4066Sahrens nvlist_t *tryconfig, *config; 851fa9e4066Sahrens int error; 852fa9e4066Sahrens 853990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 854990b4856Slling &tryconfig)) != 0) 855fa9e4066Sahrens return (error); 856fa9e4066Sahrens 857fa9e4066Sahrens config = spa_tryimport(tryconfig); 858fa9e4066Sahrens 859fa9e4066Sahrens nvlist_free(tryconfig); 860fa9e4066Sahrens 861fa9e4066Sahrens if (config == NULL) 862fa9e4066Sahrens return (EINVAL); 863fa9e4066Sahrens 864e9dbad6fSeschrock error = put_nvlist(zc, config); 865fa9e4066Sahrens nvlist_free(config); 866fa9e4066Sahrens 867fa9e4066Sahrens return (error); 868fa9e4066Sahrens } 869fa9e4066Sahrens 870fa9e4066Sahrens static int 871fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 872fa9e4066Sahrens { 873fa9e4066Sahrens spa_t *spa; 874fa9e4066Sahrens int error; 875fa9e4066Sahrens 87606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 87706eeb2adSek return (error); 87806eeb2adSek 879bb8b5132Sek mutex_enter(&spa_namespace_lock); 88006eeb2adSek error = spa_scrub(spa, zc->zc_cookie, B_FALSE); 881bb8b5132Sek mutex_exit(&spa_namespace_lock); 88206eeb2adSek 88306eeb2adSek spa_close(spa, FTAG); 88406eeb2adSek 885fa9e4066Sahrens return (error); 886fa9e4066Sahrens } 887fa9e4066Sahrens 888fa9e4066Sahrens static int 889fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 890fa9e4066Sahrens { 891fa9e4066Sahrens spa_t *spa; 892fa9e4066Sahrens int error; 893fa9e4066Sahrens 894fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 895fa9e4066Sahrens if (error == 0) { 896fa9e4066Sahrens spa_freeze(spa); 897fa9e4066Sahrens spa_close(spa, FTAG); 898fa9e4066Sahrens } 899fa9e4066Sahrens return (error); 900fa9e4066Sahrens } 901fa9e4066Sahrens 902eaca9bbdSeschrock static int 903eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 904eaca9bbdSeschrock { 905eaca9bbdSeschrock spa_t *spa; 906eaca9bbdSeschrock int error; 907eaca9bbdSeschrock 90806eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 90906eeb2adSek return (error); 91006eeb2adSek 911558d2d50Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 912558d2d50Slling spa_close(spa, FTAG); 913558d2d50Slling return (EINVAL); 914558d2d50Slling } 915558d2d50Slling 916990b4856Slling spa_upgrade(spa, zc->zc_cookie); 91706eeb2adSek spa_close(spa, FTAG); 91806eeb2adSek 91906eeb2adSek return (error); 92006eeb2adSek } 92106eeb2adSek 92206eeb2adSek static int 92306eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 92406eeb2adSek { 92506eeb2adSek spa_t *spa; 92606eeb2adSek char *hist_buf; 92706eeb2adSek uint64_t size; 92806eeb2adSek int error; 92906eeb2adSek 93006eeb2adSek if ((size = zc->zc_history_len) == 0) 93106eeb2adSek return (EINVAL); 93206eeb2adSek 93306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 93406eeb2adSek return (error); 93506eeb2adSek 936e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 937d7306b64Sek spa_close(spa, FTAG); 938d7306b64Sek return (ENOTSUP); 939d7306b64Sek } 940d7306b64Sek 94106eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 94206eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 94306eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 944ecd6cf80Smarks error = xcopyout(hist_buf, 945ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 94606eeb2adSek zc->zc_history_len); 94706eeb2adSek } 94806eeb2adSek 94906eeb2adSek spa_close(spa, FTAG); 95006eeb2adSek kmem_free(hist_buf, size); 95106eeb2adSek return (error); 95206eeb2adSek } 95306eeb2adSek 95455434c77Sek static int 95555434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 95655434c77Sek { 95755434c77Sek int error; 95855434c77Sek 959b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 96055434c77Sek return (error); 96155434c77Sek 96255434c77Sek return (0); 96355434c77Sek } 96455434c77Sek 96555434c77Sek static int 96655434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 96755434c77Sek { 96855434c77Sek objset_t *osp; 96955434c77Sek int error; 97055434c77Sek 97155434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 97255434c77Sek DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) 97355434c77Sek return (error); 97455434c77Sek 97555434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 97655434c77Sek sizeof (zc->zc_value)); 97755434c77Sek dmu_objset_close(osp); 97855434c77Sek 97955434c77Sek return (error); 98055434c77Sek } 98155434c77Sek 982fa9e4066Sahrens static int 983fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 984fa9e4066Sahrens { 985fa9e4066Sahrens spa_t *spa; 986fa9e4066Sahrens int error; 987fa94a07fSbrendan nvlist_t *config, **l2cache; 988fa94a07fSbrendan uint_t nl2cache; 989fa9e4066Sahrens 990fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 991fa9e4066Sahrens if (error != 0) 992fa9e4066Sahrens return (error); 993fa9e4066Sahrens 994fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 995fa94a07fSbrendan &config); 996fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 997fa94a07fSbrendan &l2cache, &nl2cache); 998fa94a07fSbrendan 999b1b8ab34Slling /* 1000b1b8ab34Slling * A root pool with concatenated devices is not supported. 1001b1b8ab34Slling * Thus, can not add a device to a root pool with one device. 1002fa94a07fSbrendan * Allow for l2cache devices to be added. 1003b1b8ab34Slling */ 1004fa94a07fSbrendan if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0 && 1005fa94a07fSbrendan nl2cache == 0) { 1006b1b8ab34Slling spa_close(spa, FTAG); 1007b1b8ab34Slling return (EDOM); 1008b1b8ab34Slling } 1009b1b8ab34Slling 1010fa94a07fSbrendan if (error == 0) { 1011fa9e4066Sahrens error = spa_vdev_add(spa, config); 1012fa9e4066Sahrens nvlist_free(config); 1013fa9e4066Sahrens } 1014fa9e4066Sahrens spa_close(spa, FTAG); 1015fa9e4066Sahrens return (error); 1016fa9e4066Sahrens } 1017fa9e4066Sahrens 1018fa9e4066Sahrens static int 1019fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1020fa9e4066Sahrens { 102199653d4eSeschrock spa_t *spa; 102299653d4eSeschrock int error; 102399653d4eSeschrock 102499653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 102599653d4eSeschrock if (error != 0) 102699653d4eSeschrock return (error); 102799653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 102899653d4eSeschrock spa_close(spa, FTAG); 102999653d4eSeschrock return (error); 1030fa9e4066Sahrens } 1031fa9e4066Sahrens 1032fa9e4066Sahrens static int 10333d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1034fa9e4066Sahrens { 1035fa9e4066Sahrens spa_t *spa; 1036fa9e4066Sahrens int error; 10373d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1038fa9e4066Sahrens 103906eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1040fa9e4066Sahrens return (error); 10413d7072f8Seschrock switch (zc->zc_cookie) { 10423d7072f8Seschrock case VDEV_STATE_ONLINE: 10433d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 10443d7072f8Seschrock break; 1045fa9e4066Sahrens 10463d7072f8Seschrock case VDEV_STATE_OFFLINE: 10473d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 10483d7072f8Seschrock break; 1049fa9e4066Sahrens 10503d7072f8Seschrock case VDEV_STATE_FAULTED: 10513d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 10523d7072f8Seschrock break; 10533d7072f8Seschrock 10543d7072f8Seschrock case VDEV_STATE_DEGRADED: 10553d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 10563d7072f8Seschrock break; 10573d7072f8Seschrock 10583d7072f8Seschrock default: 10593d7072f8Seschrock error = EINVAL; 10603d7072f8Seschrock } 10613d7072f8Seschrock zc->zc_cookie = newstate; 1062fa9e4066Sahrens spa_close(spa, FTAG); 1063fa9e4066Sahrens return (error); 1064fa9e4066Sahrens } 1065fa9e4066Sahrens 1066fa9e4066Sahrens static int 1067fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1068fa9e4066Sahrens { 1069fa9e4066Sahrens spa_t *spa; 1070fa9e4066Sahrens int replacing = zc->zc_cookie; 1071fa9e4066Sahrens nvlist_t *config; 1072fa9e4066Sahrens int error; 1073fa9e4066Sahrens 107406eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1075fa9e4066Sahrens return (error); 1076fa9e4066Sahrens 1077990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1078990b4856Slling &config)) == 0) { 1079ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1080fa9e4066Sahrens nvlist_free(config); 1081fa9e4066Sahrens } 1082fa9e4066Sahrens 1083fa9e4066Sahrens spa_close(spa, FTAG); 1084fa9e4066Sahrens return (error); 1085fa9e4066Sahrens } 1086fa9e4066Sahrens 1087fa9e4066Sahrens static int 1088fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1089fa9e4066Sahrens { 1090fa9e4066Sahrens spa_t *spa; 1091fa9e4066Sahrens int error; 1092fa9e4066Sahrens 109306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1094fa9e4066Sahrens return (error); 1095fa9e4066Sahrens 1096ea8dc4b6Seschrock error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 1097fa9e4066Sahrens 1098fa9e4066Sahrens spa_close(spa, FTAG); 1099fa9e4066Sahrens return (error); 1100fa9e4066Sahrens } 1101fa9e4066Sahrens 1102c67d9675Seschrock static int 1103c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1104c67d9675Seschrock { 1105c67d9675Seschrock spa_t *spa; 1106e9dbad6fSeschrock char *path = zc->zc_value; 1107ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1108c67d9675Seschrock int error; 1109c67d9675Seschrock 1110c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1111c67d9675Seschrock if (error != 0) 1112c67d9675Seschrock return (error); 1113c67d9675Seschrock 1114c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1115c67d9675Seschrock spa_close(spa, FTAG); 1116c67d9675Seschrock return (error); 1117c67d9675Seschrock } 1118c67d9675Seschrock 1119de8267e0Stimh static int 1120de8267e0Stimh zfs_os_open_retry(char *name, objset_t **os) 1121de8267e0Stimh { 1122de8267e0Stimh int error; 1123de8267e0Stimh 1124de8267e0Stimh retry: 1125de8267e0Stimh error = dmu_objset_open(name, DMU_OST_ANY, 1126de8267e0Stimh DS_MODE_STANDARD | DS_MODE_READONLY, os); 1127de8267e0Stimh if (error != 0) { 1128de8267e0Stimh /* 1129de8267e0Stimh * This is ugly: dmu_objset_open() can return EBUSY if 1130de8267e0Stimh * the objset is held exclusively. Fortunately this hold is 1131de8267e0Stimh * only for a short while, so we retry here. 1132de8267e0Stimh * This avoids user code having to handle EBUSY, 1133de8267e0Stimh * for example for a "zfs list". 1134de8267e0Stimh */ 1135de8267e0Stimh if (error == EBUSY) { 1136de8267e0Stimh delay(1); 1137de8267e0Stimh goto retry; 1138de8267e0Stimh } 1139de8267e0Stimh } 1140de8267e0Stimh return (error); 1141de8267e0Stimh } 1142de8267e0Stimh 11433cb34c60Sahrens /* 11443cb34c60Sahrens * inputs: 11453cb34c60Sahrens * zc_name name of filesystem 11463cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 11473cb34c60Sahrens * 11483cb34c60Sahrens * outputs: 11493cb34c60Sahrens * zc_objset_stats stats 11503cb34c60Sahrens * zc_nvlist_dst property nvlist 11513cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 11523cb34c60Sahrens * zc_value alternate root 11533cb34c60Sahrens */ 1154fa9e4066Sahrens static int 1155fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1156fa9e4066Sahrens { 1157fa9e4066Sahrens objset_t *os = NULL; 1158fa9e4066Sahrens int error; 11597f7322feSeschrock nvlist_t *nv; 1160fa9e4066Sahrens 1161de8267e0Stimh if ((error = zfs_os_open_retry(zc->zc_name, &os)) != 0) 1162fa9e4066Sahrens return (error); 1163fa9e4066Sahrens 1164a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1165fa9e4066Sahrens 11665ad82045Snd if (zc->zc_nvlist_dst != 0 && 11677f7322feSeschrock (error = dsl_prop_get_all(os, &nv)) == 0) { 1168a2eea2e1Sahrens dmu_objset_stats(os, nv); 1169432f72fdSahrens /* 1170bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 1171432f72fdSahrens * which we aren't supposed to do with a 1172432f72fdSahrens * DS_MODE_STANDARD open, because it could be 1173432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1174432f72fdSahrens */ 1175e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1176e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1177e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1178e7437265Sahrens } 1179e9dbad6fSeschrock error = put_nvlist(zc, nv); 11807f7322feSeschrock nvlist_free(nv); 11817f7322feSeschrock } 1182fa9e4066Sahrens 1183e9dbad6fSeschrock spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); 1184ea8dc4b6Seschrock 1185fa9e4066Sahrens dmu_objset_close(os); 1186fa9e4066Sahrens return (error); 1187fa9e4066Sahrens } 1188fa9e4066Sahrens 1189de8267e0Stimh static int 1190de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1191de8267e0Stimh { 1192de8267e0Stimh uint64_t value; 1193de8267e0Stimh int error; 1194de8267e0Stimh 1195de8267e0Stimh /* 1196de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 1197de8267e0Stimh * the default value (if there is one). 1198de8267e0Stimh */ 1199de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1200de8267e0Stimh return (error); 1201de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1202de8267e0Stimh return (0); 1203de8267e0Stimh } 1204de8267e0Stimh 12053cb34c60Sahrens /* 12063cb34c60Sahrens * inputs: 12073cb34c60Sahrens * zc_name name of filesystem 1208de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 12093cb34c60Sahrens * 12103cb34c60Sahrens * outputs: 1211de8267e0Stimh * zc_nvlist_dst zpl property nvlist 1212de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 12133cb34c60Sahrens */ 1214bd00f61bSrm static int 1215de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1216bd00f61bSrm { 1217de8267e0Stimh objset_t *os; 1218de8267e0Stimh int err; 1219bd00f61bSrm 1220de8267e0Stimh if ((err = zfs_os_open_retry(zc->zc_name, &os)) != 0) 1221de8267e0Stimh return (err); 1222bd00f61bSrm 1223bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1224bd00f61bSrm 1225bd00f61bSrm /* 1226de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 1227de8267e0Stimh * which we aren't supposed to do with a DS_MODE_STANDARD 1228de8267e0Stimh * open, because it could be inconsistent. 1229bd00f61bSrm */ 1230de8267e0Stimh if (zc->zc_nvlist_dst != NULL && 1231de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 1232de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 1233de8267e0Stimh nvlist_t *nv; 1234de8267e0Stimh 1235de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1236de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1237de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1238de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1239de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1240de8267e0Stimh err = put_nvlist(zc, nv); 1241de8267e0Stimh nvlist_free(nv); 1242de8267e0Stimh } else { 1243de8267e0Stimh err = ENOENT; 1244de8267e0Stimh } 1245bd00f61bSrm dmu_objset_close(os); 1246de8267e0Stimh return (err); 1247bd00f61bSrm } 1248bd00f61bSrm 1249de8267e0Stimh /* 1250de8267e0Stimh * inputs: 1251de8267e0Stimh * zc_name name of filesystem 1252de8267e0Stimh * zc_cookie zap cursor 1253de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 1254de8267e0Stimh * 1255de8267e0Stimh * outputs: 1256de8267e0Stimh * zc_name name of next filesystem 1257de8267e0Stimh * zc_objset_stats stats 1258de8267e0Stimh * zc_nvlist_dst property nvlist 1259de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 1260de8267e0Stimh * zc_value alternate root 1261de8267e0Stimh */ 1262fa9e4066Sahrens static int 1263fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1264fa9e4066Sahrens { 126587e5029aSahrens objset_t *os; 1266fa9e4066Sahrens int error; 1267fa9e4066Sahrens char *p; 1268fa9e4066Sahrens 1269de8267e0Stimh if ((error = zfs_os_open_retry(zc->zc_name, &os)) != 0) { 127087e5029aSahrens if (error == ENOENT) 127187e5029aSahrens error = ESRCH; 127287e5029aSahrens return (error); 1273fa9e4066Sahrens } 1274fa9e4066Sahrens 1275fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1276fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1277fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1278fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1279fa9e4066Sahrens 1280fa9e4066Sahrens do { 128187e5029aSahrens error = dmu_dir_list_next(os, 128287e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 128387e5029aSahrens NULL, &zc->zc_cookie); 1284fa9e4066Sahrens if (error == ENOENT) 1285fa9e4066Sahrens error = ESRCH; 128687e5029aSahrens } while (error == 0 && !INGLOBALZONE(curproc) && 1287fa9e4066Sahrens !zone_dataset_visible(zc->zc_name, NULL)); 1288fa9e4066Sahrens 1289fa9e4066Sahrens /* 129087e5029aSahrens * If it's a hidden dataset (ie. with a '$' in its name), don't 129187e5029aSahrens * try to get stats for it. Userland will skip over it. 1292fa9e4066Sahrens */ 129387e5029aSahrens if (error == 0 && strchr(zc->zc_name, '$') == NULL) 129487e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1295fa9e4066Sahrens 129687e5029aSahrens dmu_objset_close(os); 1297fa9e4066Sahrens return (error); 1298fa9e4066Sahrens } 1299fa9e4066Sahrens 13003cb34c60Sahrens /* 13013cb34c60Sahrens * inputs: 13023cb34c60Sahrens * zc_name name of filesystem 13033cb34c60Sahrens * zc_cookie zap cursor 13043cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13053cb34c60Sahrens * 13063cb34c60Sahrens * outputs: 13073cb34c60Sahrens * zc_name name of next snapshot 13083cb34c60Sahrens * zc_objset_stats stats 13093cb34c60Sahrens * zc_nvlist_dst property nvlist 13103cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 13113cb34c60Sahrens * zc_value alternate root 13123cb34c60Sahrens */ 1313fa9e4066Sahrens static int 1314fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1315fa9e4066Sahrens { 131687e5029aSahrens objset_t *os; 1317fa9e4066Sahrens int error; 1318fa9e4066Sahrens 1319de8267e0Stimh if ((error = zfs_os_open_retry(zc->zc_name, &os)) != 0) { 1320fa9e4066Sahrens if (error == ENOENT) 132187e5029aSahrens error = ESRCH; 1322fa9e4066Sahrens return (error); 1323fa9e4066Sahrens } 1324fa9e4066Sahrens 1325b81d61a6Slling /* 1326b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1327b81d61a6Slling * so exit immediately. 1328b81d61a6Slling */ 1329b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 133087e5029aSahrens dmu_objset_close(os); 1331b81d61a6Slling return (ESRCH); 1332fa9e4066Sahrens } 1333fa9e4066Sahrens 133487e5029aSahrens error = dmu_snapshot_list_next(os, 133587e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 1336b38f0970Sck zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 133787e5029aSahrens if (error == ENOENT) 133887e5029aSahrens error = ESRCH; 1339fa9e4066Sahrens 134087e5029aSahrens if (error == 0) 134187e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1342fa9e4066Sahrens 13433cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 13443cb34c60Sahrens if (error != 0) 13453cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 13463cb34c60Sahrens 134787e5029aSahrens dmu_objset_close(os); 1348fa9e4066Sahrens return (error); 1349fa9e4066Sahrens } 1350fa9e4066Sahrens 1351fa9e4066Sahrens static int 135291ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1353fa9e4066Sahrens { 1354e9dbad6fSeschrock nvpair_t *elem; 1355e9dbad6fSeschrock int error; 1356e9dbad6fSeschrock uint64_t intval; 1357e9dbad6fSeschrock char *strval; 1358e9dbad6fSeschrock 1359ecd6cf80Smarks /* 1360ecd6cf80Smarks * First validate permission to set all of the properties 1361ecd6cf80Smarks */ 1362e9dbad6fSeschrock elem = NULL; 1363e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1364db870a07Sahrens const char *propname = nvpair_name(elem); 1365db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1366e9dbad6fSeschrock 1367990b4856Slling if (prop == ZPROP_INVAL) { 1368e9dbad6fSeschrock /* 1369e9dbad6fSeschrock * If this is a user-defined property, it must be a 1370e9dbad6fSeschrock * string, and there is no further validation to do. 1371e9dbad6fSeschrock */ 1372e9dbad6fSeschrock if (!zfs_prop_user(propname) || 1373e9dbad6fSeschrock nvpair_type(elem) != DATA_TYPE_STRING) 1374e9dbad6fSeschrock return (EINVAL); 1375e9dbad6fSeschrock 1376da6c28aaSamw if (error = zfs_secpolicy_write_perms(name, 1377da6c28aaSamw ZFS_DELEG_PERM_USERPROP, CRED())) 1378db870a07Sahrens return (error); 1379ecd6cf80Smarks continue; 1380e9dbad6fSeschrock } 1381fa9e4066Sahrens 138291ebeef5Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1383db870a07Sahrens return (error); 1384db870a07Sahrens 1385e9dbad6fSeschrock /* 1386db870a07Sahrens * Check that this value is valid for this pool version 1387e9dbad6fSeschrock */ 1388e9dbad6fSeschrock switch (prop) { 1389c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1390c9431fa1Sahl /* 1391c9431fa1Sahl * If the user specified gzip compression, make sure 1392c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1393c9431fa1Sahl * we'll catch them later. 1394c9431fa1Sahl */ 1395c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1396c9431fa1Sahl nvpair_value_uint64(elem, &intval) == 0 && 1397c9431fa1Sahl intval >= ZIO_COMPRESS_GZIP_1 && 1398c9431fa1Sahl intval <= ZIO_COMPRESS_GZIP_9) { 1399da6c28aaSamw if (zfs_check_version(name, 1400da6c28aaSamw SPA_VERSION_GZIP_COMPRESSION)) 1401da6c28aaSamw return (ENOTSUP); 1402c9431fa1Sahl } 1403c9431fa1Sahl break; 140440feaa91Sahrens 140540feaa91Sahrens case ZFS_PROP_COPIES: 1406da6c28aaSamw if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS)) 1407da6c28aaSamw return (ENOTSUP); 140840feaa91Sahrens break; 1409*9e6eda55Smarks 1410*9e6eda55Smarks case ZFS_PROP_SHARESMB: 1411*9e6eda55Smarks if (zpl_check_version(name, ZPL_VERSION_FUID)) 1412*9e6eda55Smarks return (ENOTSUP); 1413*9e6eda55Smarks break; 141440feaa91Sahrens } 1415da6c28aaSamw if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1416da6c28aaSamw return (error); 1417ecd6cf80Smarks } 1418ecd6cf80Smarks 1419ecd6cf80Smarks elem = NULL; 1420ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1421db870a07Sahrens const char *propname = nvpair_name(elem); 1422db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1423ecd6cf80Smarks 1424990b4856Slling if (prop == ZPROP_INVAL) { 1425ecd6cf80Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 1426ecd6cf80Smarks error = dsl_prop_set(name, propname, 1, 1427ecd6cf80Smarks strlen(strval) + 1, strval); 1428ecd6cf80Smarks if (error == 0) 1429ecd6cf80Smarks continue; 1430ecd6cf80Smarks else 1431ecd6cf80Smarks return (error); 1432ecd6cf80Smarks } 1433e9dbad6fSeschrock 1434e9dbad6fSeschrock switch (prop) { 1435e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1436e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1437e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 1438e9dbad6fSeschrock return (error); 1439e9dbad6fSeschrock break; 1440e9dbad6fSeschrock 1441a9799022Sck case ZFS_PROP_REFQUOTA: 1442a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1443a9799022Sck (error = dsl_dataset_set_quota(name, intval)) != 0) 1444a9799022Sck return (error); 1445a9799022Sck break; 1446a9799022Sck 1447e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1448e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1449e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1450e9dbad6fSeschrock intval)) != 0) 1451e9dbad6fSeschrock return (error); 1452e9dbad6fSeschrock break; 1453e9dbad6fSeschrock 1454a9799022Sck case ZFS_PROP_REFRESERVATION: 1455a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1456a9799022Sck (error = dsl_dataset_set_reservation(name, 1457a9799022Sck intval)) != 0) 1458a9799022Sck return (error); 1459a9799022Sck break; 1460a9799022Sck 1461e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1462e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 146391ebeef5Sahrens (error = zvol_set_volsize(name, 146491ebeef5Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 1465e9dbad6fSeschrock return (error); 1466e9dbad6fSeschrock break; 1467e9dbad6fSeschrock 1468e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1469e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1470e7437265Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 1471e7437265Sahrens return (error); 1472e7437265Sahrens break; 1473e7437265Sahrens 1474e7437265Sahrens case ZFS_PROP_VERSION: 1475e7437265Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1476e7437265Sahrens (error = zfs_set_version(name, intval)) != 0) 1477e9dbad6fSeschrock return (error); 1478e9dbad6fSeschrock break; 1479e9dbad6fSeschrock 1480e9dbad6fSeschrock default: 1481e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1482e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 148391ebeef5Sahrens PROP_TYPE_STRING) 1484e9dbad6fSeschrock return (EINVAL); 1485acd76fe5Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 1486acd76fe5Seschrock if ((error = dsl_prop_set(name, 1487e9dbad6fSeschrock nvpair_name(elem), 1, strlen(strval) + 1, 1488acd76fe5Seschrock strval)) != 0) 1489acd76fe5Seschrock return (error); 1490e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1491a2eea2e1Sahrens const char *unused; 1492a2eea2e1Sahrens 1493acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1494e9dbad6fSeschrock 1495e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 149691ebeef5Sahrens case PROP_TYPE_NUMBER: 1497e9dbad6fSeschrock break; 149891ebeef5Sahrens case PROP_TYPE_STRING: 1499acd76fe5Seschrock return (EINVAL); 150091ebeef5Sahrens case PROP_TYPE_INDEX: 1501acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 1502acd76fe5Seschrock intval, &unused) != 0) 1503acd76fe5Seschrock return (EINVAL); 1504e9dbad6fSeschrock break; 1505e9dbad6fSeschrock default: 1506e7437265Sahrens cmn_err(CE_PANIC, 1507e7437265Sahrens "unknown property type"); 1508e9dbad6fSeschrock break; 1509e9dbad6fSeschrock } 1510e9dbad6fSeschrock 1511acd76fe5Seschrock if ((error = dsl_prop_set(name, propname, 1512acd76fe5Seschrock 8, 1, &intval)) != 0) 1513acd76fe5Seschrock return (error); 1514e9dbad6fSeschrock } else { 1515e9dbad6fSeschrock return (EINVAL); 1516e9dbad6fSeschrock } 1517e9dbad6fSeschrock break; 1518e9dbad6fSeschrock } 1519e9dbad6fSeschrock } 1520e9dbad6fSeschrock 1521e9dbad6fSeschrock return (0); 1522fa9e4066Sahrens } 1523fa9e4066Sahrens 15243cb34c60Sahrens /* 15253cb34c60Sahrens * inputs: 15263cb34c60Sahrens * zc_name name of filesystem 15273cb34c60Sahrens * zc_value name of property to inherit 15283cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 15293cb34c60Sahrens * 15303cb34c60Sahrens * outputs: none 15313cb34c60Sahrens */ 1532fa9e4066Sahrens static int 1533e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1534fa9e4066Sahrens { 1535e9dbad6fSeschrock nvlist_t *nvl; 1536e9dbad6fSeschrock int error; 1537e9dbad6fSeschrock 1538990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1539990b4856Slling &nvl)) != 0) 1540e9dbad6fSeschrock return (error); 1541e9dbad6fSeschrock 154291ebeef5Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1543ecd6cf80Smarks 1544e9dbad6fSeschrock nvlist_free(nvl); 1545e9dbad6fSeschrock return (error); 1546fa9e4066Sahrens } 1547fa9e4066Sahrens 15483cb34c60Sahrens /* 15493cb34c60Sahrens * inputs: 15503cb34c60Sahrens * zc_name name of filesystem 15513cb34c60Sahrens * zc_value name of property to inherit 15523cb34c60Sahrens * 15533cb34c60Sahrens * outputs: none 15543cb34c60Sahrens */ 1555e45ce728Sahrens static int 1556e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 1557e45ce728Sahrens { 1558e45ce728Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 1559e45ce728Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1560e45ce728Sahrens } 1561e45ce728Sahrens 1562b1b8ab34Slling static int 156311a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1564b1b8ab34Slling { 1565990b4856Slling nvlist_t *props; 1566b1b8ab34Slling spa_t *spa; 1567990b4856Slling int error; 1568b1b8ab34Slling 1569990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1570990b4856Slling &props))) 1571b1b8ab34Slling return (error); 1572b1b8ab34Slling 1573b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1574990b4856Slling nvlist_free(props); 1575b1b8ab34Slling return (error); 1576b1b8ab34Slling } 1577b1b8ab34Slling 1578990b4856Slling error = spa_prop_set(spa, props); 1579b1b8ab34Slling 1580990b4856Slling nvlist_free(props); 1581b1b8ab34Slling spa_close(spa, FTAG); 1582b1b8ab34Slling 1583b1b8ab34Slling return (error); 1584b1b8ab34Slling } 1585b1b8ab34Slling 1586b1b8ab34Slling static int 158711a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1588b1b8ab34Slling { 1589b1b8ab34Slling spa_t *spa; 1590b1b8ab34Slling int error; 1591b1b8ab34Slling nvlist_t *nvp = NULL; 1592b1b8ab34Slling 1593b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1594b1b8ab34Slling return (error); 1595b1b8ab34Slling 1596990b4856Slling error = spa_prop_get(spa, &nvp); 1597b1b8ab34Slling 1598b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1599b1b8ab34Slling error = put_nvlist(zc, nvp); 1600b1b8ab34Slling else 1601b1b8ab34Slling error = EFAULT; 1602b1b8ab34Slling 1603b1b8ab34Slling spa_close(spa, FTAG); 1604b1b8ab34Slling 1605b1b8ab34Slling if (nvp) 1606b1b8ab34Slling nvlist_free(nvp); 1607b1b8ab34Slling return (error); 1608b1b8ab34Slling } 1609b1b8ab34Slling 1610ecd6cf80Smarks static int 1611ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1612ecd6cf80Smarks { 1613ecd6cf80Smarks nvlist_t *nvp; 1614ecd6cf80Smarks int error; 1615ecd6cf80Smarks uint32_t uid; 1616ecd6cf80Smarks uint32_t gid; 1617ecd6cf80Smarks uint32_t *groups; 1618ecd6cf80Smarks uint_t group_cnt; 1619ecd6cf80Smarks cred_t *usercred; 1620ecd6cf80Smarks 1621990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1622990b4856Slling &nvp)) != 0) { 1623ecd6cf80Smarks return (error); 1624ecd6cf80Smarks } 1625ecd6cf80Smarks 1626ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1627ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 1628ecd6cf80Smarks nvlist_free(nvp); 1629ecd6cf80Smarks return (EPERM); 1630ecd6cf80Smarks } 1631ecd6cf80Smarks 1632ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1633ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 1634ecd6cf80Smarks nvlist_free(nvp); 1635ecd6cf80Smarks return (EPERM); 1636ecd6cf80Smarks } 1637ecd6cf80Smarks 1638ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1639ecd6cf80Smarks &groups, &group_cnt)) != 0) { 1640ecd6cf80Smarks nvlist_free(nvp); 1641ecd6cf80Smarks return (EPERM); 1642ecd6cf80Smarks } 1643ecd6cf80Smarks usercred = cralloc(); 1644ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 1645ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1646ecd6cf80Smarks nvlist_free(nvp); 1647ecd6cf80Smarks crfree(usercred); 1648ecd6cf80Smarks return (EPERM); 1649ecd6cf80Smarks } 1650ecd6cf80Smarks nvlist_free(nvp); 1651ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 165291ebeef5Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 1653ecd6cf80Smarks crfree(usercred); 1654ecd6cf80Smarks return (error); 1655ecd6cf80Smarks } 1656ecd6cf80Smarks 16573cb34c60Sahrens /* 16583cb34c60Sahrens * inputs: 16593cb34c60Sahrens * zc_name name of filesystem 16603cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 16613cb34c60Sahrens * zc_perm_action allow/unallow flag 16623cb34c60Sahrens * 16633cb34c60Sahrens * outputs: none 16643cb34c60Sahrens */ 1665ecd6cf80Smarks static int 1666ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 1667ecd6cf80Smarks { 1668ecd6cf80Smarks int error; 1669ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 1670ecd6cf80Smarks 1671990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1672990b4856Slling &fsaclnv)) != 0) 1673ecd6cf80Smarks return (error); 1674ecd6cf80Smarks 1675ecd6cf80Smarks /* 1676ecd6cf80Smarks * Verify nvlist is constructed correctly 1677ecd6cf80Smarks */ 1678ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1679ecd6cf80Smarks nvlist_free(fsaclnv); 1680ecd6cf80Smarks return (EINVAL); 1681ecd6cf80Smarks } 1682ecd6cf80Smarks 1683ecd6cf80Smarks /* 1684ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 1685ecd6cf80Smarks * that user is allowed to hand out each permission in 1686ecd6cf80Smarks * the nvlist(s) 1687ecd6cf80Smarks */ 1688ecd6cf80Smarks 168991ebeef5Sahrens error = secpolicy_zfs(CRED()); 1690ecd6cf80Smarks if (error) { 169191ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 169291ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 169391ebeef5Sahrens fsaclnv, CRED()); 169491ebeef5Sahrens } else { 169591ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 169691ebeef5Sahrens fsaclnv, CRED()); 169791ebeef5Sahrens } 1698ecd6cf80Smarks } 1699ecd6cf80Smarks 1700ecd6cf80Smarks if (error == 0) 1701ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1702ecd6cf80Smarks 1703ecd6cf80Smarks nvlist_free(fsaclnv); 1704ecd6cf80Smarks return (error); 1705ecd6cf80Smarks } 1706ecd6cf80Smarks 17073cb34c60Sahrens /* 17083cb34c60Sahrens * inputs: 17093cb34c60Sahrens * zc_name name of filesystem 17103cb34c60Sahrens * 17113cb34c60Sahrens * outputs: 17123cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 17133cb34c60Sahrens */ 1714ecd6cf80Smarks static int 1715ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 1716ecd6cf80Smarks { 1717ecd6cf80Smarks nvlist_t *nvp; 1718ecd6cf80Smarks int error; 1719ecd6cf80Smarks 1720ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1721ecd6cf80Smarks error = put_nvlist(zc, nvp); 1722ecd6cf80Smarks nvlist_free(nvp); 1723ecd6cf80Smarks } 1724ecd6cf80Smarks 1725ecd6cf80Smarks return (error); 1726ecd6cf80Smarks } 1727ecd6cf80Smarks 17283cb34c60Sahrens /* 17293cb34c60Sahrens * inputs: 17303cb34c60Sahrens * zc_name name of volume 17313cb34c60Sahrens * 17323cb34c60Sahrens * outputs: none 17333cb34c60Sahrens */ 1734fa9e4066Sahrens static int 1735fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1736fa9e4066Sahrens { 173791ebeef5Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1738fa9e4066Sahrens } 1739fa9e4066Sahrens 17403cb34c60Sahrens /* 17413cb34c60Sahrens * inputs: 17423cb34c60Sahrens * zc_name name of volume 17433cb34c60Sahrens * 17443cb34c60Sahrens * outputs: none 17453cb34c60Sahrens */ 1746fa9e4066Sahrens static int 1747fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1748fa9e4066Sahrens { 1749e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 1750fa9e4066Sahrens } 1751fa9e4066Sahrens 1752fa9e4066Sahrens /* 1753fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1754fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 1755fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 1756fa9e4066Sahrens */ 1757fa9e4066Sahrens static vfs_t * 1758fa9e4066Sahrens zfs_get_vfs(const char *resource) 1759fa9e4066Sahrens { 1760fa9e4066Sahrens struct vfs *vfsp; 1761fa9e4066Sahrens struct vfs *vfs_found = NULL; 1762fa9e4066Sahrens 1763fa9e4066Sahrens vfs_list_read_lock(); 1764fa9e4066Sahrens vfsp = rootvfs; 1765fa9e4066Sahrens do { 1766fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1767fa9e4066Sahrens VFS_HOLD(vfsp); 1768fa9e4066Sahrens vfs_found = vfsp; 1769fa9e4066Sahrens break; 1770fa9e4066Sahrens } 1771fa9e4066Sahrens vfsp = vfsp->vfs_next; 1772fa9e4066Sahrens } while (vfsp != rootvfs); 1773fa9e4066Sahrens vfs_list_unlock(); 1774fa9e4066Sahrens return (vfs_found); 1775fa9e4066Sahrens } 1776fa9e4066Sahrens 1777ecd6cf80Smarks /* ARGSUSED */ 1778fa9e4066Sahrens static void 1779ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1780fa9e4066Sahrens { 1781da6c28aaSamw zfs_creat_t *zct = arg; 1782da6c28aaSamw 1783de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 1784da6c28aaSamw } 1785da6c28aaSamw 1786de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 1787da6c28aaSamw 1788da6c28aaSamw /* 1789de8267e0Stimh * inputs: 1790de8267e0Stimh * createprops list of properties requested by creator 1791de8267e0Stimh * dataset name of dataset we are creating 1792de8267e0Stimh * 1793de8267e0Stimh * outputs: 1794de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 1795da6c28aaSamw * 1796de8267e0Stimh * Determine the settings for utf8only, normalization and 1797de8267e0Stimh * casesensitivity. Specific values may have been requested by the 1798de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 1799de8267e0Stimh * the file system is of too early a vintage, a creator can not 1800de8267e0Stimh * request settings for these properties, even if the requested 1801de8267e0Stimh * setting is the default value. We don't actually want to create dsl 1802de8267e0Stimh * properties for these, so remove them from the source nvlist after 1803de8267e0Stimh * processing. 1804da6c28aaSamw */ 1805da6c28aaSamw static int 1806de8267e0Stimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 1807de8267e0Stimh nvlist_t *zplprops, uint64_t zplver) 1808da6c28aaSamw { 1809de8267e0Stimh objset_t *os; 1810da6c28aaSamw char parentname[MAXNAMELEN]; 1811da6c28aaSamw char *cp; 1812de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 1813de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 1814de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 1815de8267e0Stimh int error = 0; 1816da6c28aaSamw 1817de8267e0Stimh ASSERT(zplprops != NULL); 1818da6c28aaSamw 1819de8267e0Stimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 1820de8267e0Stimh cp = strrchr(parentname, '/'); 1821de8267e0Stimh ASSERT(cp != NULL); 1822de8267e0Stimh cp[0] = '\0'; 1823da6c28aaSamw 1824de8267e0Stimh /* 1825de8267e0Stimh * Pull out creator prop choices, if any. 1826de8267e0Stimh */ 1827de8267e0Stimh if (createprops) { 1828de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1829de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 1830de8267e0Stimh (void) nvlist_remove_all(createprops, 1831de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 1832de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1833de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 1834de8267e0Stimh (void) nvlist_remove_all(createprops, 1835de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1836de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1837de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 1838de8267e0Stimh (void) nvlist_remove_all(createprops, 1839de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 1840de8267e0Stimh } 1841da6c28aaSamw 1842c2a93d44Stimh /* 1843de8267e0Stimh * If the file system or pool is version is too "young" to 1844de8267e0Stimh * support normalization and the creator tried to set a value 1845de8267e0Stimh * for one of the props, error out. We only need check the 1846de8267e0Stimh * ZPL version because we've already checked by now that the 1847de8267e0Stimh * SPA version is compatible with the selected ZPL version. 1848c2a93d44Stimh */ 1849de8267e0Stimh if (zplver < ZPL_VERSION_NORMALIZATION && 1850de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 1851de8267e0Stimh sense != ZFS_PROP_UNDEFINED)) 1852de8267e0Stimh return (ENOTSUP); 1853c2a93d44Stimh 1854de8267e0Stimh /* 1855de8267e0Stimh * Put the version in the zplprops 1856de8267e0Stimh */ 1857de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1858de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 1859da6c28aaSamw 1860de8267e0Stimh /* 1861de8267e0Stimh * Open parent object set so we can inherit zplprop values if 1862de8267e0Stimh * necessary. 1863de8267e0Stimh */ 1864de8267e0Stimh if ((error = zfs_os_open_retry(parentname, &os)) != 0) 1865da6c28aaSamw return (error); 1866da6c28aaSamw 1867de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 1868de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 1869de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1870de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 1871da6c28aaSamw 1872c2a93d44Stimh /* 1873de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 1874c2a93d44Stimh */ 1875de8267e0Stimh if (norm) 1876de8267e0Stimh u8 = 1; 1877de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 1878de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 1879de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1880de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 1881de8267e0Stimh 1882de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 1883de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 1884de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1885de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 1886c2a93d44Stimh 1887de8267e0Stimh dmu_objset_close(os); 1888da6c28aaSamw return (0); 1889fa9e4066Sahrens } 1890fa9e4066Sahrens 18913cb34c60Sahrens /* 18923cb34c60Sahrens * inputs: 18933cb34c60Sahrens * zc_objset_type type of objset to create (fs vs zvol) 18943cb34c60Sahrens * zc_name name of new objset 18953cb34c60Sahrens * zc_value name of snapshot to clone from (may be empty) 18963cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 18973cb34c60Sahrens * 1898de8267e0Stimh * outputs: none 18993cb34c60Sahrens */ 1900fa9e4066Sahrens static int 1901fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 1902fa9e4066Sahrens { 1903fa9e4066Sahrens objset_t *clone; 1904fa9e4066Sahrens int error = 0; 1905da6c28aaSamw zfs_creat_t zct; 1906ecd6cf80Smarks nvlist_t *nvprops = NULL; 1907ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 1908fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 1909fa9e4066Sahrens 1910fa9e4066Sahrens switch (type) { 1911fa9e4066Sahrens 1912fa9e4066Sahrens case DMU_OST_ZFS: 1913fa9e4066Sahrens cbfunc = zfs_create_cb; 1914fa9e4066Sahrens break; 1915fa9e4066Sahrens 1916fa9e4066Sahrens case DMU_OST_ZVOL: 1917fa9e4066Sahrens cbfunc = zvol_create_cb; 1918fa9e4066Sahrens break; 1919fa9e4066Sahrens 1920fa9e4066Sahrens default: 19211d452cf5Sahrens cbfunc = NULL; 1922fa9e4066Sahrens } 1923f18faf3fSek if (strchr(zc->zc_name, '@') || 1924f18faf3fSek strchr(zc->zc_name, '%')) 19251d452cf5Sahrens return (EINVAL); 1926fa9e4066Sahrens 1927e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 1928990b4856Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1929990b4856Slling &nvprops)) != 0) 1930e9dbad6fSeschrock return (error); 1931e9dbad6fSeschrock 1932de8267e0Stimh zct.zct_zplprops = NULL; 1933da6c28aaSamw zct.zct_props = nvprops; 1934da6c28aaSamw 1935e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1936fa9e4066Sahrens /* 1937fa9e4066Sahrens * We're creating a clone of an existing snapshot. 1938fa9e4066Sahrens */ 1939e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1940e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 1941ecd6cf80Smarks nvlist_free(nvprops); 1942fa9e4066Sahrens return (EINVAL); 1943e9dbad6fSeschrock } 1944fa9e4066Sahrens 1945e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 1946fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 1947e9dbad6fSeschrock if (error) { 1948ecd6cf80Smarks nvlist_free(nvprops); 1949fa9e4066Sahrens return (error); 1950e9dbad6fSeschrock } 1951fa9e4066Sahrens error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); 1952da6c28aaSamw if (error) { 1953da6c28aaSamw dmu_objset_close(clone); 1954da6c28aaSamw nvlist_free(nvprops); 1955da6c28aaSamw return (error); 1956da6c28aaSamw } 1957fa9e4066Sahrens dmu_objset_close(clone); 1958fa9e4066Sahrens } else { 1959e9dbad6fSeschrock if (cbfunc == NULL) { 1960ecd6cf80Smarks nvlist_free(nvprops); 19611d452cf5Sahrens return (EINVAL); 1962e9dbad6fSeschrock } 19635c5460e9Seschrock 1964e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 1965e9dbad6fSeschrock uint64_t volsize, volblocksize; 1966e9dbad6fSeschrock 1967ecd6cf80Smarks if (nvprops == NULL || 1968ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 1969e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1970e9dbad6fSeschrock &volsize) != 0) { 1971ecd6cf80Smarks nvlist_free(nvprops); 1972e9dbad6fSeschrock return (EINVAL); 1973e9dbad6fSeschrock } 1974e9dbad6fSeschrock 1975ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 1976e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1977e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 1978ecd6cf80Smarks nvlist_free(nvprops); 1979e9dbad6fSeschrock return (EINVAL); 1980e9dbad6fSeschrock } 1981e9dbad6fSeschrock 1982e9dbad6fSeschrock if (error != 0) 1983e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 1984e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 1985e9dbad6fSeschrock 1986e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 1987e9dbad6fSeschrock volblocksize)) != 0 || 1988e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 1989e9dbad6fSeschrock volblocksize)) != 0) { 1990ecd6cf80Smarks nvlist_free(nvprops); 19915c5460e9Seschrock return (error); 1992e9dbad6fSeschrock } 1993e7437265Sahrens } else if (type == DMU_OST_ZFS) { 1994e7437265Sahrens uint64_t version; 1995da6c28aaSamw int error; 1996da6c28aaSamw 1997de8267e0Stimh /* 1998de8267e0Stimh * Default ZPL version to non-FUID capable if the 1999de8267e0Stimh * pool is not upgraded to support FUIDs. 2000de8267e0Stimh */ 2001de8267e0Stimh if (zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) 2002de8267e0Stimh version = ZPL_VERSION_FUID - 1; 2003de8267e0Stimh else 2004de8267e0Stimh version = ZPL_VERSION; 2005de8267e0Stimh 2006de8267e0Stimh /* 2007de8267e0Stimh * Potentially override default ZPL version based 2008de8267e0Stimh * on creator's request. 2009de8267e0Stimh */ 2010de8267e0Stimh (void) nvlist_lookup_uint64(nvprops, 2011da6c28aaSamw zfs_prop_to_name(ZFS_PROP_VERSION), &version); 2012e7437265Sahrens 2013de8267e0Stimh /* 2014de8267e0Stimh * Make sure version we ended up with is kosher 2015de8267e0Stimh */ 2016de8267e0Stimh if ((version < ZPL_VERSION_INITIAL || 2017de8267e0Stimh version > ZPL_VERSION) || 2018de8267e0Stimh (version >= ZPL_VERSION_FUID && 2019de8267e0Stimh zfs_check_version(zc->zc_name, SPA_VERSION_FUID))) { 2020da6c28aaSamw nvlist_free(nvprops); 2021da6c28aaSamw return (ENOTSUP); 2022e7437265Sahrens } 2023e9dbad6fSeschrock 2024da6c28aaSamw /* 2025da6c28aaSamw * We have to have normalization and 2026da6c28aaSamw * case-folding flags correct when we do the 2027da6c28aaSamw * file system creation, so go figure them out 2028de8267e0Stimh * now. 2029da6c28aaSamw */ 2030de8267e0Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 2031de8267e0Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 2032de8267e0Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 2033de8267e0Stimh zct.zct_zplprops, version); 2034da6c28aaSamw if (error != 0) { 2035da6c28aaSamw nvlist_free(nvprops); 2036de8267e0Stimh nvlist_free(zct.zct_zplprops); 2037da6c28aaSamw return (error); 2038da6c28aaSamw } 2039da6c28aaSamw } 2040e9dbad6fSeschrock error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, 2041da6c28aaSamw &zct); 2042de8267e0Stimh nvlist_free(zct.zct_zplprops); 2043fa9e4066Sahrens } 2044e9dbad6fSeschrock 2045e9dbad6fSeschrock /* 2046e9dbad6fSeschrock * It would be nice to do this atomically. 2047e9dbad6fSeschrock */ 2048e9dbad6fSeschrock if (error == 0) { 204991ebeef5Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 2050e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 2051e9dbad6fSeschrock } 2052e9dbad6fSeschrock 2053ecd6cf80Smarks nvlist_free(nvprops); 2054fa9e4066Sahrens return (error); 2055fa9e4066Sahrens } 2056fa9e4066Sahrens 20573cb34c60Sahrens /* 20583cb34c60Sahrens * inputs: 20593cb34c60Sahrens * zc_name name of filesystem 20603cb34c60Sahrens * zc_value short name of snapshot 20613cb34c60Sahrens * zc_cookie recursive flag 20623cb34c60Sahrens * 20633cb34c60Sahrens * outputs: none 20643cb34c60Sahrens */ 2065fa9e4066Sahrens static int 20661d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 2067fa9e4066Sahrens { 2068e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 20691d452cf5Sahrens return (EINVAL); 20701d452cf5Sahrens return (dmu_objset_snapshot(zc->zc_name, 2071e9dbad6fSeschrock zc->zc_value, zc->zc_cookie)); 20721d452cf5Sahrens } 2073fa9e4066Sahrens 2074cdf5b4caSmmusante int 20751d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 20761d452cf5Sahrens { 20771d452cf5Sahrens char *snapname = arg; 20781d452cf5Sahrens char *cp; 20790b69c2f0Sahrens vfs_t *vfsp = NULL; 20801d452cf5Sahrens 20811d452cf5Sahrens /* 20821d452cf5Sahrens * Snapshots (which are under .zfs control) must be unmounted 20831d452cf5Sahrens * before they can be destroyed. 20841d452cf5Sahrens */ 20851d452cf5Sahrens 20861d452cf5Sahrens if (snapname) { 20871d452cf5Sahrens (void) strcat(name, "@"); 20881d452cf5Sahrens (void) strcat(name, snapname); 20891d452cf5Sahrens vfsp = zfs_get_vfs(name); 20901d452cf5Sahrens cp = strchr(name, '@'); 20911d452cf5Sahrens *cp = '\0'; 20920b69c2f0Sahrens } else if (strchr(name, '@')) { 20931d452cf5Sahrens vfsp = zfs_get_vfs(name); 20941d452cf5Sahrens } 20951d452cf5Sahrens 20961d452cf5Sahrens if (vfsp) { 2097fa9e4066Sahrens /* 20981d452cf5Sahrens * Always force the unmount for snapshots. 2099fa9e4066Sahrens */ 21001d452cf5Sahrens int flag = MS_FORCE; 21011d452cf5Sahrens int err; 21021d452cf5Sahrens 21031d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 2104fa9e4066Sahrens VFS_RELE(vfsp); 21051d452cf5Sahrens return (err); 2106fa9e4066Sahrens } 21071d452cf5Sahrens VFS_RELE(vfsp); 21081d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 21091d452cf5Sahrens return (err); 21101d452cf5Sahrens } 21111d452cf5Sahrens return (0); 21121d452cf5Sahrens } 21131d452cf5Sahrens 21143cb34c60Sahrens /* 21153cb34c60Sahrens * inputs: 21163cb34c60Sahrens * zc_name name of filesystem 21173cb34c60Sahrens * zc_value short name of snapshot 21183cb34c60Sahrens * 21193cb34c60Sahrens * outputs: none 21203cb34c60Sahrens */ 21211d452cf5Sahrens static int 21221d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 21231d452cf5Sahrens { 21241d452cf5Sahrens int err; 21251d452cf5Sahrens 2126e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 21271d452cf5Sahrens return (EINVAL); 21281d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 2129e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 21301d452cf5Sahrens if (err) 21311d452cf5Sahrens return (err); 2132e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 21331d452cf5Sahrens } 21341d452cf5Sahrens 21353cb34c60Sahrens /* 21363cb34c60Sahrens * inputs: 21373cb34c60Sahrens * zc_name name of dataset to destroy 21383cb34c60Sahrens * zc_objset_type type of objset 21393cb34c60Sahrens * 21403cb34c60Sahrens * outputs: none 21413cb34c60Sahrens */ 21421d452cf5Sahrens static int 21431d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 21441d452cf5Sahrens { 21451d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 21461d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 21471d452cf5Sahrens if (err) 21481d452cf5Sahrens return (err); 2149fa9e4066Sahrens } 2150fa9e4066Sahrens 2151fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 2152fa9e4066Sahrens } 2153fa9e4066Sahrens 21543cb34c60Sahrens /* 21553cb34c60Sahrens * inputs: 21564ccbb6e7Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 21573cb34c60Sahrens * 21583cb34c60Sahrens * outputs: none 21593cb34c60Sahrens */ 2160fa9e4066Sahrens static int 2161fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2162fa9e4066Sahrens { 21634ccbb6e7Sahrens objset_t *os; 21644ccbb6e7Sahrens int error; 21654ccbb6e7Sahrens zfsvfs_t *zfsvfs = NULL; 21664ccbb6e7Sahrens 21674ccbb6e7Sahrens /* 21684ccbb6e7Sahrens * Get the zfsvfs for the receiving objset. There 21694ccbb6e7Sahrens * won't be one if we're operating on a zvol, if the 21704ccbb6e7Sahrens * objset doesn't exist yet, or is not mounted. 21714ccbb6e7Sahrens */ 21724ccbb6e7Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 21734ccbb6e7Sahrens DS_MODE_STANDARD, &os); 21744ccbb6e7Sahrens if (error) 21754ccbb6e7Sahrens return (error); 21764ccbb6e7Sahrens 21774ccbb6e7Sahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 21784ccbb6e7Sahrens mutex_enter(&os->os->os_user_ptr_lock); 21794ccbb6e7Sahrens zfsvfs = dmu_objset_get_user(os); 21804ccbb6e7Sahrens if (zfsvfs != NULL) 21814ccbb6e7Sahrens VFS_HOLD(zfsvfs->z_vfs); 21824ccbb6e7Sahrens mutex_exit(&os->os->os_user_ptr_lock); 21834ccbb6e7Sahrens } 21844ccbb6e7Sahrens 21854ccbb6e7Sahrens if (zfsvfs != NULL) { 21864ccbb6e7Sahrens char osname[MAXNAMELEN]; 21874ccbb6e7Sahrens int mode; 21884ccbb6e7Sahrens 21894ccbb6e7Sahrens VERIFY3U(0, ==, zfs_suspend_fs(zfsvfs, osname, &mode)); 21904ccbb6e7Sahrens ASSERT(strcmp(osname, zc->zc_name) == 0); 21914ccbb6e7Sahrens error = dmu_objset_rollback(os); 21924ccbb6e7Sahrens VERIFY3U(0, ==, zfs_resume_fs(zfsvfs, osname, mode)); 21934ccbb6e7Sahrens 21944ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 21954ccbb6e7Sahrens } else { 21964ccbb6e7Sahrens error = dmu_objset_rollback(os); 21974ccbb6e7Sahrens } 21984ccbb6e7Sahrens /* Note, the dmu_objset_rollback() closes the objset for us. */ 21994ccbb6e7Sahrens 22004ccbb6e7Sahrens return (error); 2201fa9e4066Sahrens } 2202fa9e4066Sahrens 22033cb34c60Sahrens /* 22043cb34c60Sahrens * inputs: 22053cb34c60Sahrens * zc_name old name of dataset 22063cb34c60Sahrens * zc_value new name of dataset 22073cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 22083cb34c60Sahrens * 22093cb34c60Sahrens * outputs: none 22103cb34c60Sahrens */ 2211fa9e4066Sahrens static int 2212fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2213fa9e4066Sahrens { 22147f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 2215cdf5b4caSmmusante 2216e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2217f18faf3fSek if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2218f18faf3fSek strchr(zc->zc_value, '%')) 2219fa9e4066Sahrens return (EINVAL); 2220fa9e4066Sahrens 2221cdf5b4caSmmusante /* 2222cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 2223cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 2224cdf5b4caSmmusante * to unmount. 2225cdf5b4caSmmusante */ 2226cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2227fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 22281d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 22291d452cf5Sahrens if (err) 22301d452cf5Sahrens return (err); 2231fa9e4066Sahrens } 2232fa9e4066Sahrens 2233cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2234fa9e4066Sahrens } 2235fa9e4066Sahrens 22363cb34c60Sahrens /* 22373cb34c60Sahrens * inputs: 22383cb34c60Sahrens * zc_name name of containing filesystem 22393cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 22403cb34c60Sahrens * zc_value name of snapshot to create 22413cb34c60Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 22423cb34c60Sahrens * zc_cookie file descriptor to recv from 22433cb34c60Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 22443cb34c60Sahrens * zc_guid force flag 22453cb34c60Sahrens * 22463cb34c60Sahrens * outputs: 22473cb34c60Sahrens * zc_cookie number of bytes read 22483cb34c60Sahrens */ 2249fa9e4066Sahrens static int 22503cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2251fa9e4066Sahrens { 2252fa9e4066Sahrens file_t *fp; 2253f18faf3fSek objset_t *os; 22543cb34c60Sahrens dmu_recv_cookie_t drc; 2255f18faf3fSek zfsvfs_t *zfsvfs = NULL; 2256f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 2257f18faf3fSek int error, fd; 22583cb34c60Sahrens offset_t off; 22593cb34c60Sahrens nvlist_t *props = NULL; 22603cb34c60Sahrens objset_t *origin = NULL; 22613cb34c60Sahrens char *tosnap; 22623cb34c60Sahrens char tofs[ZFS_MAXNAMELEN]; 2263fa9e4066Sahrens 22643ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2265f18faf3fSek strchr(zc->zc_value, '@') == NULL || 2266f18faf3fSek strchr(zc->zc_value, '%')) 22673ccfa83cSahrens return (EINVAL); 22683ccfa83cSahrens 22693cb34c60Sahrens (void) strcpy(tofs, zc->zc_value); 22703cb34c60Sahrens tosnap = strchr(tofs, '@'); 22713cb34c60Sahrens *tosnap = '\0'; 22723cb34c60Sahrens tosnap++; 22733cb34c60Sahrens 22743cb34c60Sahrens if (zc->zc_nvlist_src != NULL && 22753cb34c60Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 22763cb34c60Sahrens &props)) != 0) 22773cb34c60Sahrens return (error); 22783cb34c60Sahrens 2279fa9e4066Sahrens fd = zc->zc_cookie; 2280fa9e4066Sahrens fp = getf(fd); 22813cb34c60Sahrens if (fp == NULL) { 22823cb34c60Sahrens nvlist_free(props); 2283fa9e4066Sahrens return (EBADF); 22843cb34c60Sahrens } 2285f18faf3fSek 2286f18faf3fSek /* 2287f18faf3fSek * Get the zfsvfs for the receiving objset. There 2288f18faf3fSek * won't be one if we're operating on a zvol, if the 2289f18faf3fSek * objset doesn't exist yet, or is not mounted. 2290f18faf3fSek */ 22913cb34c60Sahrens 22924ccbb6e7Sahrens error = dmu_objset_open(tofs, DMU_OST_ZFS, 2293f18faf3fSek DS_MODE_STANDARD | DS_MODE_READONLY, &os); 2294f18faf3fSek if (!error) { 22954ccbb6e7Sahrens mutex_enter(&os->os->os_user_ptr_lock); 22964ccbb6e7Sahrens zfsvfs = dmu_objset_get_user(os); 22974ccbb6e7Sahrens if (zfsvfs != NULL) 22984ccbb6e7Sahrens VFS_HOLD(zfsvfs->z_vfs); 22994ccbb6e7Sahrens mutex_exit(&os->os->os_user_ptr_lock); 2300f18faf3fSek dmu_objset_close(os); 2301f18faf3fSek } 2302f18faf3fSek 23033cb34c60Sahrens if (zc->zc_string[0]) { 23043cb34c60Sahrens error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 23053cb34c60Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &origin); 23063cb34c60Sahrens if (error) { 23073cb34c60Sahrens if (zfsvfs != NULL) 23083cb34c60Sahrens VFS_RELE(zfsvfs->z_vfs); 23093cb34c60Sahrens nvlist_free(props); 23103cb34c60Sahrens releasef(fd); 23113cb34c60Sahrens return (error); 23123cb34c60Sahrens } 23133cb34c60Sahrens } 23143cb34c60Sahrens 23153cb34c60Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 23163cb34c60Sahrens force, origin, zfsvfs != NULL, &drc); 23173cb34c60Sahrens if (origin) 23183cb34c60Sahrens dmu_objset_close(origin); 23193cb34c60Sahrens if (error) { 23203cb34c60Sahrens if (zfsvfs != NULL) 23213cb34c60Sahrens VFS_RELE(zfsvfs->z_vfs); 23223cb34c60Sahrens nvlist_free(props); 23233cb34c60Sahrens releasef(fd); 23243cb34c60Sahrens return (error); 23253cb34c60Sahrens } 2326f18faf3fSek 2327f18faf3fSek /* 23283cb34c60Sahrens * If properties are supplied, they are to completely replace 23293cb34c60Sahrens * the existing ones; "inherit" any existing properties. 2330f18faf3fSek */ 23313cb34c60Sahrens if (props) { 23323cb34c60Sahrens objset_t *os; 23333cb34c60Sahrens nvlist_t *nv = NULL; 23343cb34c60Sahrens 23353cb34c60Sahrens error = dmu_objset_open(tofs, DMU_OST_ANY, 23363cb34c60Sahrens DS_MODE_STANDARD | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 23373cb34c60Sahrens &os); 23383cb34c60Sahrens if (error == 0) { 23393cb34c60Sahrens error = dsl_prop_get_all(os, &nv); 23403cb34c60Sahrens dmu_objset_close(os); 23413cb34c60Sahrens } 23423cb34c60Sahrens if (error == 0) { 23433cb34c60Sahrens nvpair_t *elem; 23444ccbb6e7Sahrens zfs_cmd_t *zc2; 23454ccbb6e7Sahrens zc2 = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 23463cb34c60Sahrens 23474ccbb6e7Sahrens (void) strcpy(zc2->zc_name, tofs); 23483cb34c60Sahrens for (elem = nvlist_next_nvpair(nv, NULL); elem; 23493cb34c60Sahrens elem = nvlist_next_nvpair(nv, elem)) { 23504ccbb6e7Sahrens (void) strcpy(zc2->zc_value, nvpair_name(elem)); 23514ccbb6e7Sahrens if (zfs_secpolicy_inherit(zc2, CRED()) == 0) 23524ccbb6e7Sahrens (void) zfs_ioc_inherit_prop(zc2); 2353f18faf3fSek } 23544ccbb6e7Sahrens kmem_free(zc2, sizeof (zfs_cmd_t)); 2355f18faf3fSek } 23563cb34c60Sahrens if (nv) 23573cb34c60Sahrens nvlist_free(nv); 23583cb34c60Sahrens } 23593cb34c60Sahrens 23603cb34c60Sahrens /* 23613cb34c60Sahrens * Set properties. Note, we ignore errors. Would be better to 23623cb34c60Sahrens * do best-effort in zfs_set_prop_nvlist, too. 23633cb34c60Sahrens */ 23643cb34c60Sahrens (void) zfs_set_prop_nvlist(tofs, props); 23653cb34c60Sahrens nvlist_free(props); 23663cb34c60Sahrens 23673cb34c60Sahrens off = fp->f_offset; 23683cb34c60Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 2369a2eea2e1Sahrens 23703cb34c60Sahrens if (error == 0) { 23713cb34c60Sahrens if (zfsvfs != NULL) { 23723cb34c60Sahrens char osname[MAXNAMELEN]; 23733cb34c60Sahrens int mode; 23743cb34c60Sahrens 23753cb34c60Sahrens (void) zfs_suspend_fs(zfsvfs, osname, &mode); 23763cb34c60Sahrens error = dmu_recv_end(&drc); 23773cb34c60Sahrens error |= zfs_resume_fs(zfsvfs, osname, mode); 23783cb34c60Sahrens } else { 23793cb34c60Sahrens error = dmu_recv_end(&drc); 23803cb34c60Sahrens } 2381f18faf3fSek } 2382f18faf3fSek if (zfsvfs != NULL) 2383f18faf3fSek VFS_RELE(zfsvfs->z_vfs); 23843cb34c60Sahrens 23853cb34c60Sahrens zc->zc_cookie = off - fp->f_offset; 23863cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 23873cb34c60Sahrens fp->f_offset = off; 2388a2eea2e1Sahrens 2389fa9e4066Sahrens releasef(fd); 2390fa9e4066Sahrens return (error); 2391fa9e4066Sahrens } 2392fa9e4066Sahrens 23933cb34c60Sahrens /* 23943cb34c60Sahrens * inputs: 23953cb34c60Sahrens * zc_name name of snapshot to send 23963cb34c60Sahrens * zc_value short name of incremental fromsnap (may be empty) 23973cb34c60Sahrens * zc_cookie file descriptor to send stream to 23983cb34c60Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 23993cb34c60Sahrens * 24003cb34c60Sahrens * outputs: none 24013cb34c60Sahrens */ 2402fa9e4066Sahrens static int 24033cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2404fa9e4066Sahrens { 2405fa9e4066Sahrens objset_t *fromsnap = NULL; 2406fa9e4066Sahrens objset_t *tosnap; 2407fa9e4066Sahrens file_t *fp; 2408fa9e4066Sahrens int error; 24093cb34c60Sahrens offset_t off; 2410fa9e4066Sahrens 2411fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 2412fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); 2413fa9e4066Sahrens if (error) 2414fa9e4066Sahrens return (error); 2415fa9e4066Sahrens 2416e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 2417a2eea2e1Sahrens char buf[MAXPATHLEN]; 2418a2eea2e1Sahrens char *cp; 2419a2eea2e1Sahrens 2420a2eea2e1Sahrens (void) strncpy(buf, zc->zc_name, sizeof (buf)); 2421a2eea2e1Sahrens cp = strchr(buf, '@'); 2422a2eea2e1Sahrens if (cp) 2423a2eea2e1Sahrens *(cp+1) = 0; 2424a2eea2e1Sahrens (void) strncat(buf, zc->zc_value, sizeof (buf)); 2425a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 2426fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); 2427fa9e4066Sahrens if (error) { 2428fa9e4066Sahrens dmu_objset_close(tosnap); 2429fa9e4066Sahrens return (error); 2430fa9e4066Sahrens } 2431fa9e4066Sahrens } 2432fa9e4066Sahrens 2433fa9e4066Sahrens fp = getf(zc->zc_cookie); 2434fa9e4066Sahrens if (fp == NULL) { 2435fa9e4066Sahrens dmu_objset_close(tosnap); 2436fa9e4066Sahrens if (fromsnap) 2437fa9e4066Sahrens dmu_objset_close(fromsnap); 2438fa9e4066Sahrens return (EBADF); 2439fa9e4066Sahrens } 2440fa9e4066Sahrens 24413cb34c60Sahrens off = fp->f_offset; 24423cb34c60Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 2443fa9e4066Sahrens 24443cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 24453cb34c60Sahrens fp->f_offset = off; 2446fa9e4066Sahrens releasef(zc->zc_cookie); 2447fa9e4066Sahrens if (fromsnap) 2448fa9e4066Sahrens dmu_objset_close(fromsnap); 2449fa9e4066Sahrens dmu_objset_close(tosnap); 2450fa9e4066Sahrens return (error); 2451fa9e4066Sahrens } 2452fa9e4066Sahrens 2453ea8dc4b6Seschrock static int 2454ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 2455ea8dc4b6Seschrock { 2456ea8dc4b6Seschrock int id, error; 2457ea8dc4b6Seschrock 2458ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2459ea8dc4b6Seschrock &zc->zc_inject_record); 2460ea8dc4b6Seschrock 2461ea8dc4b6Seschrock if (error == 0) 2462ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 2463ea8dc4b6Seschrock 2464ea8dc4b6Seschrock return (error); 2465ea8dc4b6Seschrock } 2466ea8dc4b6Seschrock 2467ea8dc4b6Seschrock static int 2468ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 2469ea8dc4b6Seschrock { 2470ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 2471ea8dc4b6Seschrock } 2472ea8dc4b6Seschrock 2473ea8dc4b6Seschrock static int 2474ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2475ea8dc4b6Seschrock { 2476ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2477ea8dc4b6Seschrock int error; 2478ea8dc4b6Seschrock 2479ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2480ea8dc4b6Seschrock &zc->zc_inject_record); 2481ea8dc4b6Seschrock 2482ea8dc4b6Seschrock zc->zc_guid = id; 2483ea8dc4b6Seschrock 2484ea8dc4b6Seschrock return (error); 2485ea8dc4b6Seschrock } 2486ea8dc4b6Seschrock 2487ea8dc4b6Seschrock static int 2488ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2489ea8dc4b6Seschrock { 2490ea8dc4b6Seschrock spa_t *spa; 2491ea8dc4b6Seschrock int error; 2492e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2493ea8dc4b6Seschrock 2494ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2495ea8dc4b6Seschrock return (error); 2496ea8dc4b6Seschrock 2497e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2498ea8dc4b6Seschrock &count); 2499ea8dc4b6Seschrock if (error == 0) 2500e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2501ea8dc4b6Seschrock else 2502e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2503ea8dc4b6Seschrock 2504ea8dc4b6Seschrock spa_close(spa, FTAG); 2505ea8dc4b6Seschrock 2506ea8dc4b6Seschrock return (error); 2507ea8dc4b6Seschrock } 2508ea8dc4b6Seschrock 2509ea8dc4b6Seschrock static int 2510ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2511ea8dc4b6Seschrock { 2512ea8dc4b6Seschrock spa_t *spa; 2513ea8dc4b6Seschrock vdev_t *vd; 25143d7072f8Seschrock uint64_t txg; 2515bb8b5132Sek int error; 2516ea8dc4b6Seschrock 2517ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2518ea8dc4b6Seschrock return (error); 2519ea8dc4b6Seschrock 25200a4e9518Sgw /* 25210a4e9518Sgw * Try to resume any I/Os which may have been suspended 25220a4e9518Sgw * as a result of a complete pool failure. 25230a4e9518Sgw */ 25240a4e9518Sgw if (!list_is_empty(&spa->spa_zio_list)) { 25250a4e9518Sgw if (zio_vdev_resume_io(spa) != 0) { 25260a4e9518Sgw spa_close(spa, FTAG); 25270a4e9518Sgw return (EIO); 25280a4e9518Sgw } 25290a4e9518Sgw } 25300a4e9518Sgw 25313d7072f8Seschrock txg = spa_vdev_enter(spa); 2532ea8dc4b6Seschrock 2533e9dbad6fSeschrock if (zc->zc_guid == 0) { 2534ea8dc4b6Seschrock vd = NULL; 2535e9dbad6fSeschrock } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { 2536fa94a07fSbrendan spa_aux_vdev_t *sav; 2537fa94a07fSbrendan int i; 2538fa94a07fSbrendan 2539fa94a07fSbrendan /* 2540fa94a07fSbrendan * Check if this is an l2cache device. 2541fa94a07fSbrendan */ 2542fa94a07fSbrendan ASSERT(spa != NULL); 2543fa94a07fSbrendan sav = &spa->spa_l2cache; 2544fa94a07fSbrendan for (i = 0; i < sav->sav_count; i++) { 2545fa94a07fSbrendan if (sav->sav_vdevs[i]->vdev_guid == zc->zc_guid) { 2546fa94a07fSbrendan vd = sav->sav_vdevs[i]; 2547fa94a07fSbrendan break; 2548fa94a07fSbrendan } 2549fa94a07fSbrendan } 2550fa94a07fSbrendan 2551fa94a07fSbrendan if (vd == NULL) { 2552fa94a07fSbrendan (void) spa_vdev_exit(spa, NULL, txg, ENODEV); 2553fa94a07fSbrendan spa_close(spa, FTAG); 2554fa94a07fSbrendan return (ENODEV); 2555fa94a07fSbrendan } 2556ea8dc4b6Seschrock } 2557ea8dc4b6Seschrock 25580a4e9518Sgw vdev_clear(spa, vd, B_TRUE); 2559ea8dc4b6Seschrock 25603d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, 0); 2561ea8dc4b6Seschrock 2562ea8dc4b6Seschrock spa_close(spa, FTAG); 2563ea8dc4b6Seschrock 2564ea8dc4b6Seschrock return (0); 2565ea8dc4b6Seschrock } 2566ea8dc4b6Seschrock 25673cb34c60Sahrens /* 25683cb34c60Sahrens * inputs: 25693cb34c60Sahrens * zc_name name of filesystem 25703cb34c60Sahrens * zc_value name of origin snapshot 25713cb34c60Sahrens * 25723cb34c60Sahrens * outputs: none 25733cb34c60Sahrens */ 257499653d4eSeschrock static int 257599653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 257699653d4eSeschrock { 25770b69c2f0Sahrens char *cp; 25780b69c2f0Sahrens 25790b69c2f0Sahrens /* 25800b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 25810b69c2f0Sahrens * it's easier. 25820b69c2f0Sahrens */ 2583e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 25840b69c2f0Sahrens if (cp) 25850b69c2f0Sahrens *cp = '\0'; 2586e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 25870b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 258899653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 258999653d4eSeschrock } 259099653d4eSeschrock 2591ecd6cf80Smarks /* 2592ecd6cf80Smarks * We don't want to have a hard dependency 2593ecd6cf80Smarks * against some special symbols in sharefs 2594da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 2595ecd6cf80Smarks * the first file system is shared. 2596da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 2597ecd6cf80Smarks */ 2598da6c28aaSamw int (*znfsexport_fs)(void *arg); 2599ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2600da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 2601da6c28aaSamw 2602da6c28aaSamw int zfs_nfsshare_inited; 2603da6c28aaSamw int zfs_smbshare_inited; 2604ecd6cf80Smarks 2605ecd6cf80Smarks ddi_modhandle_t nfs_mod; 2606ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 2607da6c28aaSamw ddi_modhandle_t smbsrv_mod; 2608ecd6cf80Smarks kmutex_t zfs_share_lock; 2609ecd6cf80Smarks 2610da6c28aaSamw static int 2611da6c28aaSamw zfs_init_sharefs() 2612da6c28aaSamw { 2613da6c28aaSamw int error; 2614da6c28aaSamw 2615da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 2616da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 2617da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 2618da6c28aaSamw ddi_modopen("fs/sharefs", 2619da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2620da6c28aaSamw return (ENOSYS); 2621da6c28aaSamw } 2622da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 2623da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2624da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2625da6c28aaSamw return (ENOSYS); 2626da6c28aaSamw } 2627da6c28aaSamw return (0); 2628da6c28aaSamw } 2629da6c28aaSamw 2630ecd6cf80Smarks static int 2631ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 2632ecd6cf80Smarks { 2633ecd6cf80Smarks int error; 2634ecd6cf80Smarks int opcode; 2635ecd6cf80Smarks 2636da6c28aaSamw switch (zc->zc_share.z_sharetype) { 2637da6c28aaSamw case ZFS_SHARE_NFS: 2638da6c28aaSamw case ZFS_UNSHARE_NFS: 2639da6c28aaSamw if (zfs_nfsshare_inited == 0) { 2640da6c28aaSamw mutex_enter(&zfs_share_lock); 2641da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 2642da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2643da6c28aaSamw mutex_exit(&zfs_share_lock); 2644da6c28aaSamw return (ENOSYS); 2645da6c28aaSamw } 2646da6c28aaSamw if (znfsexport_fs == NULL && 2647da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 2648da6c28aaSamw ddi_modsym(nfs_mod, 2649da6c28aaSamw "nfs_export", &error)) == NULL)) { 2650da6c28aaSamw mutex_exit(&zfs_share_lock); 2651da6c28aaSamw return (ENOSYS); 2652da6c28aaSamw } 2653da6c28aaSamw error = zfs_init_sharefs(); 2654da6c28aaSamw if (error) { 2655da6c28aaSamw mutex_exit(&zfs_share_lock); 2656da6c28aaSamw return (ENOSYS); 2657da6c28aaSamw } 2658da6c28aaSamw zfs_nfsshare_inited = 1; 2659ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2660ecd6cf80Smarks } 2661da6c28aaSamw break; 2662da6c28aaSamw case ZFS_SHARE_SMB: 2663da6c28aaSamw case ZFS_UNSHARE_SMB: 2664da6c28aaSamw if (zfs_smbshare_inited == 0) { 2665da6c28aaSamw mutex_enter(&zfs_share_lock); 2666da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 2667da6c28aaSamw ddi_modopen("drv/smbsrv", 2668da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2669da6c28aaSamw mutex_exit(&zfs_share_lock); 2670da6c28aaSamw return (ENOSYS); 2671da6c28aaSamw } 2672da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 2673da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 2674da6c28aaSamw "lmshrd_share_upcall", &error)) == NULL)) { 2675da6c28aaSamw mutex_exit(&zfs_share_lock); 2676da6c28aaSamw return (ENOSYS); 2677da6c28aaSamw } 2678da6c28aaSamw error = zfs_init_sharefs(); 2679da6c28aaSamw if (error) { 2680da6c28aaSamw mutex_exit(&zfs_share_lock); 2681da6c28aaSamw return (ENOSYS); 2682da6c28aaSamw } 2683da6c28aaSamw zfs_smbshare_inited = 1; 2684ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2685ecd6cf80Smarks } 2686da6c28aaSamw break; 2687da6c28aaSamw default: 2688da6c28aaSamw return (EINVAL); 2689da6c28aaSamw } 2690ecd6cf80Smarks 2691da6c28aaSamw switch (zc->zc_share.z_sharetype) { 2692da6c28aaSamw case ZFS_SHARE_NFS: 2693da6c28aaSamw case ZFS_UNSHARE_NFS: 2694da6c28aaSamw if (error = 2695da6c28aaSamw znfsexport_fs((void *) 2696da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 2697da6c28aaSamw return (error); 2698da6c28aaSamw break; 2699da6c28aaSamw case ZFS_SHARE_SMB: 2700da6c28aaSamw case ZFS_UNSHARE_SMB: 2701da6c28aaSamw if (error = zsmbexport_fs((void *) 2702da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 2703da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 2704da6c28aaSamw B_TRUE : B_FALSE)) { 2705da6c28aaSamw return (error); 2706ecd6cf80Smarks } 2707da6c28aaSamw break; 2708ecd6cf80Smarks } 2709ecd6cf80Smarks 2710da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 2711da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 2712ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 2713ecd6cf80Smarks 2714da6c28aaSamw /* 2715da6c28aaSamw * Add or remove share from sharetab 2716da6c28aaSamw */ 2717ecd6cf80Smarks error = zshare_fs(opcode, 2718ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 2719ecd6cf80Smarks zc->zc_share.z_sharemax); 2720ecd6cf80Smarks 2721ecd6cf80Smarks return (error); 2722ecd6cf80Smarks 2723ecd6cf80Smarks } 2724ecd6cf80Smarks 2725ecd6cf80Smarks /* 27262a6b87f0Sek * pool create, destroy, and export don't log the history as part of 27272a6b87f0Sek * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 27282a6b87f0Sek * do the logging of those commands. 2729ecd6cf80Smarks */ 2730fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 2731228975ccSek { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2732e7437265Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2733e7437265Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2734e7437265Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2735e7437265Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 2736e7437265Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2737e7437265Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2738e7437265Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2739e7437265Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2740e7437265Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2741e7437265Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2742e7437265Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2743e7437265Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2744e7437265Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2745e7437265Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2746e7437265Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2747e7437265Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2748e7437265Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2749de8267e0Stimh { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2750ecd6cf80Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 2751e7437265Sahrens DATASET_NAME, B_FALSE }, 2752ecd6cf80Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 2753e7437265Sahrens DATASET_NAME, B_FALSE }, 2754e7437265Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 2755e7437265Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2756e7437265Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2757e7437265Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 2758e7437265Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2759e7437265Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 2760e7437265Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 27613cb34c60Sahrens { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 27623cb34c60Sahrens { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 2763e7437265Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2764e7437265Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2765e7437265Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2766e7437265Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 2767e7437265Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2768e7437265Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 2769e7437265Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2770e7437265Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 2771e7437265Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2772e7437265Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2773e7437265Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2774e7437265Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2775e7437265Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 2776e7437265Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2777ecd6cf80Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 2778e7437265Sahrens DATASET_NAME, B_FALSE }, 2779e45ce728Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 2780e45ce728Sahrens { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 2781fa9e4066Sahrens }; 2782fa9e4066Sahrens 2783fa9e4066Sahrens static int 2784fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2785fa9e4066Sahrens { 2786fa9e4066Sahrens zfs_cmd_t *zc; 2787fa9e4066Sahrens uint_t vec; 27881d452cf5Sahrens int error, rc; 2789fa9e4066Sahrens 2790fa9e4066Sahrens if (getminor(dev) != 0) 2791fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2792fa9e4066Sahrens 2793fa9e4066Sahrens vec = cmd - ZFS_IOC; 279491ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 2795fa9e4066Sahrens 2796fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2797fa9e4066Sahrens return (EINVAL); 2798fa9e4066Sahrens 2799fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2800fa9e4066Sahrens 2801fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2802fa9e4066Sahrens 280391ebeef5Sahrens if (error == 0) 2804ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2805fa9e4066Sahrens 2806fa9e4066Sahrens /* 2807fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2808fa9e4066Sahrens * the lower layers. 2809fa9e4066Sahrens */ 2810fa9e4066Sahrens if (error == 0) { 2811fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2812fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 2813e7437265Sahrens case POOL_NAME: 2814fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2815fa9e4066Sahrens error = EINVAL; 2816fa9e4066Sahrens break; 2817fa9e4066Sahrens 2818e7437265Sahrens case DATASET_NAME: 2819fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2820fa9e4066Sahrens error = EINVAL; 2821fa9e4066Sahrens break; 28225ad82045Snd 2823e7437265Sahrens case NO_NAME: 28245ad82045Snd break; 2825fa9e4066Sahrens } 2826fa9e4066Sahrens } 2827fa9e4066Sahrens 2828fa9e4066Sahrens if (error == 0) 2829fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2830fa9e4066Sahrens 28311d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 2832ecd6cf80Smarks if (error == 0) { 28331d452cf5Sahrens error = rc; 2834ecd6cf80Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 2835ecd6cf80Smarks zfs_log_history(zc); 2836ecd6cf80Smarks } 2837fa9e4066Sahrens 2838fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 2839fa9e4066Sahrens return (error); 2840fa9e4066Sahrens } 2841fa9e4066Sahrens 2842fa9e4066Sahrens static int 2843fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2844fa9e4066Sahrens { 2845fa9e4066Sahrens if (cmd != DDI_ATTACH) 2846fa9e4066Sahrens return (DDI_FAILURE); 2847fa9e4066Sahrens 2848fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 2849fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 2850fa9e4066Sahrens return (DDI_FAILURE); 2851fa9e4066Sahrens 2852fa9e4066Sahrens zfs_dip = dip; 2853fa9e4066Sahrens 2854fa9e4066Sahrens ddi_report_dev(dip); 2855fa9e4066Sahrens 2856fa9e4066Sahrens return (DDI_SUCCESS); 2857fa9e4066Sahrens } 2858fa9e4066Sahrens 2859fa9e4066Sahrens static int 2860fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2861fa9e4066Sahrens { 2862fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 2863fa9e4066Sahrens return (DDI_FAILURE); 2864fa9e4066Sahrens 2865fa9e4066Sahrens if (cmd != DDI_DETACH) 2866fa9e4066Sahrens return (DDI_FAILURE); 2867fa9e4066Sahrens 2868fa9e4066Sahrens zfs_dip = NULL; 2869fa9e4066Sahrens 2870fa9e4066Sahrens ddi_prop_remove_all(dip); 2871fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 2872fa9e4066Sahrens 2873fa9e4066Sahrens return (DDI_SUCCESS); 2874fa9e4066Sahrens } 2875fa9e4066Sahrens 2876fa9e4066Sahrens /*ARGSUSED*/ 2877fa9e4066Sahrens static int 2878fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2879fa9e4066Sahrens { 2880fa9e4066Sahrens switch (infocmd) { 2881fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 2882fa9e4066Sahrens *result = zfs_dip; 2883fa9e4066Sahrens return (DDI_SUCCESS); 2884fa9e4066Sahrens 2885fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 2886a0965f35Sbonwick *result = (void *)0; 2887fa9e4066Sahrens return (DDI_SUCCESS); 2888fa9e4066Sahrens } 2889fa9e4066Sahrens 2890fa9e4066Sahrens return (DDI_FAILURE); 2891fa9e4066Sahrens } 2892fa9e4066Sahrens 2893fa9e4066Sahrens /* 2894fa9e4066Sahrens * OK, so this is a little weird. 2895fa9e4066Sahrens * 2896fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 2897fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 2898fa9e4066Sahrens * 2899fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 2900fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 2901fa9e4066Sahrens */ 2902fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 2903fa9e4066Sahrens zvol_open, /* open */ 2904fa9e4066Sahrens zvol_close, /* close */ 2905fa9e4066Sahrens zvol_strategy, /* strategy */ 2906fa9e4066Sahrens nodev, /* print */ 2907fa9e4066Sahrens nodev, /* dump */ 2908fa9e4066Sahrens zvol_read, /* read */ 2909fa9e4066Sahrens zvol_write, /* write */ 2910fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 2911fa9e4066Sahrens nodev, /* devmap */ 2912fa9e4066Sahrens nodev, /* mmap */ 2913fa9e4066Sahrens nodev, /* segmap */ 2914fa9e4066Sahrens nochpoll, /* poll */ 2915fa9e4066Sahrens ddi_prop_op, /* prop_op */ 2916fa9e4066Sahrens NULL, /* streamtab */ 2917fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 2918fa9e4066Sahrens CB_REV, /* version */ 2919feb08c6bSbillm nodev, /* async read */ 2920feb08c6bSbillm nodev, /* async write */ 2921fa9e4066Sahrens }; 2922fa9e4066Sahrens 2923fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 2924fa9e4066Sahrens DEVO_REV, /* version */ 2925fa9e4066Sahrens 0, /* refcnt */ 2926fa9e4066Sahrens zfs_info, /* info */ 2927fa9e4066Sahrens nulldev, /* identify */ 2928fa9e4066Sahrens nulldev, /* probe */ 2929fa9e4066Sahrens zfs_attach, /* attach */ 2930fa9e4066Sahrens zfs_detach, /* detach */ 2931fa9e4066Sahrens nodev, /* reset */ 2932fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 2933fa9e4066Sahrens NULL /* no bus operations */ 2934fa9e4066Sahrens }; 2935fa9e4066Sahrens 2936fa9e4066Sahrens static struct modldrv zfs_modldrv = { 2937e7437265Sahrens &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, 2938e9dbad6fSeschrock &zfs_dev_ops 2939fa9e4066Sahrens }; 2940fa9e4066Sahrens 2941fa9e4066Sahrens static struct modlinkage modlinkage = { 2942fa9e4066Sahrens MODREV_1, 2943fa9e4066Sahrens (void *)&zfs_modlfs, 2944fa9e4066Sahrens (void *)&zfs_modldrv, 2945fa9e4066Sahrens NULL 2946fa9e4066Sahrens }; 2947fa9e4066Sahrens 2948ec533521Sfr 2949ec533521Sfr uint_t zfs_fsyncer_key; 2950f18faf3fSek extern uint_t rrw_tsd_key; 2951ec533521Sfr 2952fa9e4066Sahrens int 2953fa9e4066Sahrens _init(void) 2954fa9e4066Sahrens { 2955fa9e4066Sahrens int error; 2956fa9e4066Sahrens 2957a0965f35Sbonwick spa_init(FREAD | FWRITE); 2958a0965f35Sbonwick zfs_init(); 2959a0965f35Sbonwick zvol_init(); 2960a0965f35Sbonwick 2961a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 2962a0965f35Sbonwick zvol_fini(); 2963a0965f35Sbonwick zfs_fini(); 2964a0965f35Sbonwick spa_fini(); 2965fa9e4066Sahrens return (error); 2966a0965f35Sbonwick } 2967fa9e4066Sahrens 2968ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 2969f18faf3fSek tsd_create(&rrw_tsd_key, NULL); 2970ec533521Sfr 2971fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 2972fa9e4066Sahrens ASSERT(error == 0); 2973ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 2974fa9e4066Sahrens 2975fa9e4066Sahrens return (0); 2976fa9e4066Sahrens } 2977fa9e4066Sahrens 2978fa9e4066Sahrens int 2979fa9e4066Sahrens _fini(void) 2980fa9e4066Sahrens { 2981fa9e4066Sahrens int error; 2982fa9e4066Sahrens 2983ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 2984fa9e4066Sahrens return (EBUSY); 2985fa9e4066Sahrens 2986fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 2987fa9e4066Sahrens return (error); 2988fa9e4066Sahrens 2989fa9e4066Sahrens zvol_fini(); 2990fa9e4066Sahrens zfs_fini(); 2991fa9e4066Sahrens spa_fini(); 2992da6c28aaSamw if (zfs_nfsshare_inited) 2993ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 2994da6c28aaSamw if (zfs_smbshare_inited) 2995da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 2996da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 2997ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 2998fa9e4066Sahrens 2999ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 3000fa9e4066Sahrens ldi_ident_release(zfs_li); 3001fa9e4066Sahrens zfs_li = NULL; 3002ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 3003fa9e4066Sahrens 3004fa9e4066Sahrens return (error); 3005fa9e4066Sahrens } 3006fa9e4066Sahrens 3007fa9e4066Sahrens int 3008fa9e4066Sahrens _info(struct modinfo *modinfop) 3009fa9e4066Sahrens { 3010fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 3011fa9e4066Sahrens } 3012