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 /* 229e6eda55Smarks * 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 157*15e6edf1Sgw /* 158*15e6edf1Sgw * Check to see if the named dataset is currently defined as bootable 159*15e6edf1Sgw */ 160*15e6edf1Sgw static boolean_t 161*15e6edf1Sgw zfs_is_bootfs(const char *name) 162*15e6edf1Sgw { 163*15e6edf1Sgw spa_t *spa; 164*15e6edf1Sgw boolean_t ret = B_FALSE; 165*15e6edf1Sgw 166*15e6edf1Sgw if (spa_open(name, &spa, FTAG) == 0) { 167*15e6edf1Sgw if (spa->spa_bootfs) { 168*15e6edf1Sgw objset_t *os; 169*15e6edf1Sgw 170*15e6edf1Sgw if (dmu_objset_open(name, DMU_OST_ZFS, 171*15e6edf1Sgw DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 172*15e6edf1Sgw ret = (dmu_objset_id(os) == spa->spa_bootfs); 173*15e6edf1Sgw dmu_objset_close(os); 174*15e6edf1Sgw } 175*15e6edf1Sgw } 176*15e6edf1Sgw spa_close(spa, FTAG); 177*15e6edf1Sgw } 178*15e6edf1Sgw return (ret); 179*15e6edf1Sgw } 180*15e6edf1Sgw 181c2a93d44Stimh /* 182c2a93d44Stimh * zfs_check_version 183c2a93d44Stimh * 184c2a93d44Stimh * Return non-zero if the spa version is less than requested version. 185c2a93d44Stimh */ 186da6c28aaSamw static int 187da6c28aaSamw zfs_check_version(const char *name, int version) 188da6c28aaSamw { 189da6c28aaSamw 190da6c28aaSamw spa_t *spa; 191da6c28aaSamw 192da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 193da6c28aaSamw if (spa_version(spa) < version) { 194da6c28aaSamw spa_close(spa, FTAG); 195da6c28aaSamw return (1); 196da6c28aaSamw } 197da6c28aaSamw spa_close(spa, FTAG); 198da6c28aaSamw } 199da6c28aaSamw return (0); 200da6c28aaSamw } 201da6c28aaSamw 2029e6eda55Smarks /* 203745cd3c5Smaybee * zpl_earlier_version 2049e6eda55Smarks * 205745cd3c5Smaybee * Return TRUE if the ZPL version is less than requested version. 2069e6eda55Smarks */ 207745cd3c5Smaybee static boolean_t 208745cd3c5Smaybee zpl_earlier_version(const char *name, int version) 2099e6eda55Smarks { 2109e6eda55Smarks objset_t *os; 211745cd3c5Smaybee boolean_t rc = B_TRUE; 2129e6eda55Smarks 2139e6eda55Smarks if (dmu_objset_open(name, DMU_OST_ANY, 214745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 215745cd3c5Smaybee uint64_t zplversion; 2169e6eda55Smarks 217745cd3c5Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 218745cd3c5Smaybee rc = zplversion < version; 2199e6eda55Smarks dmu_objset_close(os); 2209e6eda55Smarks } 2219e6eda55Smarks return (rc); 2229e6eda55Smarks } 2239e6eda55Smarks 224228975ccSek static void 225228975ccSek zfs_log_history(zfs_cmd_t *zc) 226228975ccSek { 227228975ccSek spa_t *spa; 228228975ccSek char *buf; 229ecd6cf80Smarks 230228975ccSek if ((buf = history_str_get(zc)) == NULL) 231228975ccSek return; 232228975ccSek 233228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 234228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 235228975ccSek (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 236228975ccSek spa_close(spa, FTAG); 237228975ccSek } 238228975ccSek history_str_free(buf); 239ecd6cf80Smarks } 240ecd6cf80Smarks 241fa9e4066Sahrens /* 242fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 243fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 244fa9e4066Sahrens */ 245fa9e4066Sahrens /* ARGSUSED */ 246fa9e4066Sahrens static int 247ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 248fa9e4066Sahrens { 249fa9e4066Sahrens return (0); 250fa9e4066Sahrens } 251fa9e4066Sahrens 252fa9e4066Sahrens /* 253fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 254fa9e4066Sahrens * no privileges, but must be visible in the local zone. 255fa9e4066Sahrens */ 256fa9e4066Sahrens /* ARGSUSED */ 257fa9e4066Sahrens static int 258ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 259fa9e4066Sahrens { 260fa9e4066Sahrens if (INGLOBALZONE(curproc) || 261ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 262fa9e4066Sahrens return (0); 263fa9e4066Sahrens 264fa9e4066Sahrens return (ENOENT); 265fa9e4066Sahrens } 266fa9e4066Sahrens 267fa9e4066Sahrens static int 268fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 269fa9e4066Sahrens { 270fa9e4066Sahrens uint64_t zoned; 271fa9e4066Sahrens int writable = 1; 272fa9e4066Sahrens 273fa9e4066Sahrens /* 274fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 275fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 276fa9e4066Sahrens */ 277fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 278fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 279fa9e4066Sahrens return (ENOENT); 280fa9e4066Sahrens 281fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 282fa9e4066Sahrens return (ENOENT); 283fa9e4066Sahrens 284fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 285fa9e4066Sahrens /* 286fa9e4066Sahrens * If the fs is zoned, only root can access it from the 287fa9e4066Sahrens * global zone. 288fa9e4066Sahrens */ 289fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 290fa9e4066Sahrens return (EPERM); 291fa9e4066Sahrens } else { 292fa9e4066Sahrens /* 293fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 294fa9e4066Sahrens */ 295fa9e4066Sahrens if (!zoned) 296fa9e4066Sahrens return (EPERM); 297fa9e4066Sahrens 298fa9e4066Sahrens /* must be writable by this zone */ 299fa9e4066Sahrens if (!writable) 300fa9e4066Sahrens return (EPERM); 301fa9e4066Sahrens } 302fa9e4066Sahrens return (0); 303fa9e4066Sahrens } 304fa9e4066Sahrens 305fa9e4066Sahrens int 306ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 307fa9e4066Sahrens { 308fa9e4066Sahrens int error; 309fa9e4066Sahrens 310ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 311ecd6cf80Smarks if (error == 0) { 312ecd6cf80Smarks error = secpolicy_zfs(cr); 313db870a07Sahrens if (error) 314ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 315ecd6cf80Smarks } 316ecd6cf80Smarks return (error); 317ecd6cf80Smarks } 318ecd6cf80Smarks 319ecd6cf80Smarks static int 320ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 321ecd6cf80Smarks { 322ecd6cf80Smarks /* 323ecd6cf80Smarks * Check permissions for special properties. 324ecd6cf80Smarks */ 325ecd6cf80Smarks switch (prop) { 326ecd6cf80Smarks case ZFS_PROP_ZONED: 327ecd6cf80Smarks /* 328ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 329ecd6cf80Smarks */ 330ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 331ecd6cf80Smarks return (EPERM); 332ecd6cf80Smarks break; 333ecd6cf80Smarks 334ecd6cf80Smarks case ZFS_PROP_QUOTA: 335ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 336ecd6cf80Smarks uint64_t zoned; 337ecd6cf80Smarks char setpoint[MAXNAMELEN]; 338ecd6cf80Smarks /* 339ecd6cf80Smarks * Unprivileged users are allowed to modify the 340ecd6cf80Smarks * quota on things *under* (ie. contained by) 341ecd6cf80Smarks * the thing they own. 342ecd6cf80Smarks */ 343ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 344ecd6cf80Smarks setpoint)) 345ecd6cf80Smarks return (EPERM); 346db870a07Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 347ecd6cf80Smarks return (EPERM); 348ecd6cf80Smarks } 349db870a07Sahrens break; 350ecd6cf80Smarks } 351ecd6cf80Smarks 35291ebeef5Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 353ecd6cf80Smarks } 354ecd6cf80Smarks 355ecd6cf80Smarks int 356ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 357ecd6cf80Smarks { 358ecd6cf80Smarks int error; 359ecd6cf80Smarks 360ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 361ecd6cf80Smarks if (error) 362fa9e4066Sahrens return (error); 363fa9e4066Sahrens 364ecd6cf80Smarks /* 365ecd6cf80Smarks * permission to set permissions will be evaluated later in 366ecd6cf80Smarks * dsl_deleg_can_allow() 367ecd6cf80Smarks */ 368ecd6cf80Smarks return (0); 369ecd6cf80Smarks } 370ecd6cf80Smarks 371ecd6cf80Smarks int 372ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 373ecd6cf80Smarks { 374ecd6cf80Smarks int error; 375ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 376ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 377ecd6cf80Smarks if (error == 0) 378ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 379ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 380ecd6cf80Smarks return (error); 381ecd6cf80Smarks } 382ecd6cf80Smarks 383ecd6cf80Smarks int 384ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 385ecd6cf80Smarks { 386ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 387ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 388ecd6cf80Smarks } 389ecd6cf80Smarks 390ecd6cf80Smarks int 391ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 392ecd6cf80Smarks { 393ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 394ecd6cf80Smarks return (EPERM); 395ecd6cf80Smarks 3963cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 397ecd6cf80Smarks return (0); 398ecd6cf80Smarks } else { 399ecd6cf80Smarks vnode_t *vp; 400ecd6cf80Smarks int error; 401ecd6cf80Smarks 402ecd6cf80Smarks if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 403ecd6cf80Smarks NO_FOLLOW, NULL, &vp)) != 0) 404ecd6cf80Smarks return (error); 405ecd6cf80Smarks 406ecd6cf80Smarks /* Now make sure mntpnt and dataset are ZFS */ 407ecd6cf80Smarks 408ecd6cf80Smarks if (vp->v_vfsp->vfs_fstype != zfsfstype || 409ecd6cf80Smarks (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 410ecd6cf80Smarks zc->zc_name) != 0)) { 411ecd6cf80Smarks VN_RELE(vp); 412ecd6cf80Smarks return (EPERM); 413ecd6cf80Smarks } 414ecd6cf80Smarks 415ecd6cf80Smarks VN_RELE(vp); 416ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 417ecd6cf80Smarks ZFS_DELEG_PERM_SHARE, cr)); 418ecd6cf80Smarks } 419fa9e4066Sahrens } 420fa9e4066Sahrens 421fa9e4066Sahrens static int 422ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 423fa9e4066Sahrens { 424fa9e4066Sahrens char *cp; 425fa9e4066Sahrens 426fa9e4066Sahrens /* 427fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 428fa9e4066Sahrens */ 429ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 430ecd6cf80Smarks cp = strrchr(parent, '@'); 431fa9e4066Sahrens if (cp != NULL) { 432fa9e4066Sahrens cp[0] = '\0'; 433fa9e4066Sahrens } else { 434ecd6cf80Smarks cp = strrchr(parent, '/'); 435fa9e4066Sahrens if (cp == NULL) 436fa9e4066Sahrens return (ENOENT); 437fa9e4066Sahrens cp[0] = '\0'; 438ecd6cf80Smarks } 439ecd6cf80Smarks 440ecd6cf80Smarks return (0); 441ecd6cf80Smarks } 442ecd6cf80Smarks 443ecd6cf80Smarks int 444ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 445ecd6cf80Smarks { 446ecd6cf80Smarks int error; 447ecd6cf80Smarks 448ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 449ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 450ecd6cf80Smarks return (error); 451ecd6cf80Smarks 452ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 453ecd6cf80Smarks } 454ecd6cf80Smarks 455ecd6cf80Smarks static int 456ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 457ecd6cf80Smarks { 458ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 459ecd6cf80Smarks } 460ecd6cf80Smarks 461ecd6cf80Smarks /* 462ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 463ecd6cf80Smarks */ 464ecd6cf80Smarks /* ARGSUSED */ 465ecd6cf80Smarks static int 466ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 467ecd6cf80Smarks { 468ecd6cf80Smarks return (secpolicy_zfs(cr)); 469ecd6cf80Smarks } 470ecd6cf80Smarks 471ecd6cf80Smarks int 472ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 473ecd6cf80Smarks { 474ecd6cf80Smarks char parentname[MAXNAMELEN]; 475ecd6cf80Smarks int error; 476ecd6cf80Smarks 477ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 478ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 479ecd6cf80Smarks return (error); 480ecd6cf80Smarks 481ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 482ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 483ecd6cf80Smarks return (error); 484ecd6cf80Smarks 485ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 486ecd6cf80Smarks sizeof (parentname))) != 0) 487ecd6cf80Smarks return (error); 488ecd6cf80Smarks 489ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 490ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 491ecd6cf80Smarks return (error); 492ecd6cf80Smarks 493ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 494ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 495ecd6cf80Smarks return (error); 496ecd6cf80Smarks 497ecd6cf80Smarks return (error); 498ecd6cf80Smarks } 499ecd6cf80Smarks 500ecd6cf80Smarks static int 501ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 502ecd6cf80Smarks { 503ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 504ecd6cf80Smarks } 505ecd6cf80Smarks 506ecd6cf80Smarks static int 507ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 508ecd6cf80Smarks { 509ecd6cf80Smarks char parentname[MAXNAMELEN]; 510ecd6cf80Smarks objset_t *clone; 511ecd6cf80Smarks int error; 512ecd6cf80Smarks 513ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 514ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 515ecd6cf80Smarks if (error) 516ecd6cf80Smarks return (error); 517ecd6cf80Smarks 518ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 519745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 520ecd6cf80Smarks 521ecd6cf80Smarks if (error == 0) { 522ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 523ecd6cf80Smarks dsl_dir_t *dd; 524ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 525ecd6cf80Smarks 526ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 527745cd3c5Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 528745cd3c5Smaybee dd->dd_phys->dd_origin_obj, FTAG, &pclone); 529ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 530ecd6cf80Smarks if (error) { 531ecd6cf80Smarks dmu_objset_close(clone); 532ecd6cf80Smarks return (error); 533ecd6cf80Smarks } 534ecd6cf80Smarks 535ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 536ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 537ecd6cf80Smarks 538ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 539ecd6cf80Smarks dmu_objset_close(clone); 540745cd3c5Smaybee dsl_dataset_rele(pclone, FTAG); 541ecd6cf80Smarks if (error == 0) 542ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 543ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 544ecd6cf80Smarks } 545ecd6cf80Smarks return (error); 546ecd6cf80Smarks } 547ecd6cf80Smarks 548ecd6cf80Smarks static int 549ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 550ecd6cf80Smarks { 551ecd6cf80Smarks int error; 552ecd6cf80Smarks 553ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 554ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 555ecd6cf80Smarks return (error); 556ecd6cf80Smarks 557ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 558ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 559ecd6cf80Smarks return (error); 560ecd6cf80Smarks 561ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 562ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 563ecd6cf80Smarks } 564ecd6cf80Smarks 565ecd6cf80Smarks int 566ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 567ecd6cf80Smarks { 568ecd6cf80Smarks int error; 569ecd6cf80Smarks 570ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 571ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 572ecd6cf80Smarks return (error); 573ecd6cf80Smarks 574ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 575ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 576ecd6cf80Smarks 577ecd6cf80Smarks return (error); 578ecd6cf80Smarks } 579ecd6cf80Smarks 580ecd6cf80Smarks static int 581ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 582ecd6cf80Smarks { 583ecd6cf80Smarks 584ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 585ecd6cf80Smarks } 586ecd6cf80Smarks 587ecd6cf80Smarks static int 588ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 589ecd6cf80Smarks { 590ecd6cf80Smarks char parentname[MAXNAMELEN]; 591ecd6cf80Smarks int error; 592ecd6cf80Smarks 593ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 594ecd6cf80Smarks sizeof (parentname))) != 0) 595ecd6cf80Smarks return (error); 596fa9e4066Sahrens 597ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 598ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 599ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 600ecd6cf80Smarks return (error); 601fa9e4066Sahrens } 602fa9e4066Sahrens 603ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 604ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 605ecd6cf80Smarks return (error); 606ecd6cf80Smarks 607ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 608ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 609ecd6cf80Smarks 610ecd6cf80Smarks return (error); 611ecd6cf80Smarks } 612ecd6cf80Smarks 613ecd6cf80Smarks static int 614ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 615ecd6cf80Smarks { 616ecd6cf80Smarks int error; 617ecd6cf80Smarks 618ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 619ecd6cf80Smarks if (error) { 620ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 621ecd6cf80Smarks } 622ecd6cf80Smarks return (error); 623fa9e4066Sahrens } 624fa9e4066Sahrens 625fa9e4066Sahrens /* 626fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 627fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 628fa9e4066Sahrens */ 629fa9e4066Sahrens /* ARGSUSED */ 630fa9e4066Sahrens static int 631ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 632fa9e4066Sahrens { 633fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 634fa9e4066Sahrens return (EPERM); 635fa9e4066Sahrens 636fa9e4066Sahrens return (0); 637fa9e4066Sahrens } 638fa9e4066Sahrens 639ecd6cf80Smarks /* 640ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 641ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 642ecd6cf80Smarks * the minor nodes. 643ecd6cf80Smarks */ 644ecd6cf80Smarks static int 645ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 646ecd6cf80Smarks { 647ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 648ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 649ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 650ecd6cf80Smarks } 651ecd6cf80Smarks 652ecd6cf80Smarks return (0); 653ecd6cf80Smarks } 654ecd6cf80Smarks 655ea8dc4b6Seschrock /* 656ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 657ea8dc4b6Seschrock */ 658ea8dc4b6Seschrock /* ARGSUSED */ 659ea8dc4b6Seschrock static int 660ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 661ea8dc4b6Seschrock { 662ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 663ea8dc4b6Seschrock } 664ea8dc4b6Seschrock 665e45ce728Sahrens static int 666e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 667e45ce728Sahrens { 668e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 669e45ce728Sahrens 670990b4856Slling if (prop == ZPROP_INVAL) { 671e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 672e45ce728Sahrens return (EINVAL); 673e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 674e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 675e45ce728Sahrens } else { 676e45ce728Sahrens if (!zfs_prop_inheritable(prop)) 677e45ce728Sahrens return (EINVAL); 678e45ce728Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 679e45ce728Sahrens } 680e45ce728Sahrens } 681e45ce728Sahrens 682fa9e4066Sahrens /* 683fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 684fa9e4066Sahrens */ 685fa9e4066Sahrens static int 686990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 687fa9e4066Sahrens { 688fa9e4066Sahrens char *packed; 689fa9e4066Sahrens int error; 690990b4856Slling nvlist_t *list = NULL; 691fa9e4066Sahrens 692fa9e4066Sahrens /* 693e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 694fa9e4066Sahrens */ 695990b4856Slling if (size == 0) 696fa9e4066Sahrens return (EINVAL); 697fa9e4066Sahrens 698fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 699fa9e4066Sahrens 700990b4856Slling if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 701fa9e4066Sahrens kmem_free(packed, size); 702fa9e4066Sahrens return (error); 703fa9e4066Sahrens } 704fa9e4066Sahrens 705990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 706fa9e4066Sahrens kmem_free(packed, size); 707fa9e4066Sahrens return (error); 708fa9e4066Sahrens } 709fa9e4066Sahrens 710fa9e4066Sahrens kmem_free(packed, size); 711fa9e4066Sahrens 712990b4856Slling *nvp = list; 713fa9e4066Sahrens return (0); 714fa9e4066Sahrens } 715fa9e4066Sahrens 716e9dbad6fSeschrock static int 717e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 718e9dbad6fSeschrock { 719e9dbad6fSeschrock char *packed = NULL; 720e9dbad6fSeschrock size_t size; 721e9dbad6fSeschrock int error; 722e9dbad6fSeschrock 723e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 724e9dbad6fSeschrock 725e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 726e9dbad6fSeschrock error = ENOMEM; 727e9dbad6fSeschrock } else { 728da165920Smarks packed = kmem_alloc(size, KM_SLEEP); 729e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 730e9dbad6fSeschrock KM_SLEEP) == 0); 731e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 732e9dbad6fSeschrock size); 733e9dbad6fSeschrock kmem_free(packed, size); 734e9dbad6fSeschrock } 735e9dbad6fSeschrock 736e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 737e9dbad6fSeschrock return (error); 738e9dbad6fSeschrock } 739e9dbad6fSeschrock 740fa9e4066Sahrens static int 741fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 742fa9e4066Sahrens { 743fa9e4066Sahrens int error; 744990b4856Slling nvlist_t *config, *props = NULL; 745228975ccSek char *buf; 746fa9e4066Sahrens 747990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 748990b4856Slling &config)) 749fa9e4066Sahrens return (error); 7502a6b87f0Sek 751990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 752990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 753990b4856Slling nvlist_free(config); 754990b4856Slling return (error); 755990b4856Slling } 756990b4856Slling 7572a6b87f0Sek buf = history_str_get(zc); 758fa9e4066Sahrens 759990b4856Slling error = spa_create(zc->zc_name, config, props, buf); 760fa9e4066Sahrens 7612a6b87f0Sek if (buf != NULL) 7622a6b87f0Sek history_str_free(buf); 763990b4856Slling 764fa9e4066Sahrens nvlist_free(config); 765fa9e4066Sahrens 766990b4856Slling if (props) 767990b4856Slling nvlist_free(props); 768990b4856Slling 769fa9e4066Sahrens return (error); 770fa9e4066Sahrens } 771fa9e4066Sahrens 772fa9e4066Sahrens static int 773fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 774fa9e4066Sahrens { 775ecd6cf80Smarks int error; 776ecd6cf80Smarks zfs_log_history(zc); 777ecd6cf80Smarks error = spa_destroy(zc->zc_name); 778ecd6cf80Smarks return (error); 779fa9e4066Sahrens } 780fa9e4066Sahrens 781fa9e4066Sahrens static int 782fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 783fa9e4066Sahrens { 784fa9e4066Sahrens int error; 785990b4856Slling nvlist_t *config, *props = NULL; 786fa9e4066Sahrens uint64_t guid; 787fa9e4066Sahrens 788990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 789990b4856Slling &config)) != 0) 790990b4856Slling return (error); 791990b4856Slling 792990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 793990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 794990b4856Slling nvlist_free(config); 795fa9e4066Sahrens return (error); 796990b4856Slling } 797fa9e4066Sahrens 798fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 799ea8dc4b6Seschrock guid != zc->zc_guid) 800fa9e4066Sahrens error = EINVAL; 801c5904d13Seschrock else if (zc->zc_cookie) 802c5904d13Seschrock error = spa_import_faulted(zc->zc_name, config, 803c5904d13Seschrock props); 804fa9e4066Sahrens else 805990b4856Slling error = spa_import(zc->zc_name, config, props); 806fa9e4066Sahrens 807fa9e4066Sahrens nvlist_free(config); 808fa9e4066Sahrens 809990b4856Slling if (props) 810990b4856Slling nvlist_free(props); 811990b4856Slling 812fa9e4066Sahrens return (error); 813fa9e4066Sahrens } 814fa9e4066Sahrens 815fa9e4066Sahrens static int 816fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 817fa9e4066Sahrens { 818ecd6cf80Smarks int error; 819ecd6cf80Smarks zfs_log_history(zc); 820ecd6cf80Smarks error = spa_export(zc->zc_name, NULL); 821ecd6cf80Smarks return (error); 822fa9e4066Sahrens } 823fa9e4066Sahrens 824fa9e4066Sahrens static int 825fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 826fa9e4066Sahrens { 827fa9e4066Sahrens nvlist_t *configs; 828fa9e4066Sahrens int error; 829fa9e4066Sahrens 830fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 831fa9e4066Sahrens return (EEXIST); 832fa9e4066Sahrens 833e9dbad6fSeschrock error = put_nvlist(zc, configs); 834fa9e4066Sahrens 835fa9e4066Sahrens nvlist_free(configs); 836fa9e4066Sahrens 837fa9e4066Sahrens return (error); 838fa9e4066Sahrens } 839fa9e4066Sahrens 840fa9e4066Sahrens static int 841fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 842fa9e4066Sahrens { 843fa9e4066Sahrens nvlist_t *config; 844fa9e4066Sahrens int error; 845ea8dc4b6Seschrock int ret = 0; 846fa9e4066Sahrens 847e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 848e9dbad6fSeschrock sizeof (zc->zc_value)); 849fa9e4066Sahrens 850fa9e4066Sahrens if (config != NULL) { 851e9dbad6fSeschrock ret = put_nvlist(zc, config); 852fa9e4066Sahrens nvlist_free(config); 853ea8dc4b6Seschrock 854ea8dc4b6Seschrock /* 855ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 856ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 857ea8dc4b6Seschrock * in 'zc_cookie'. 858ea8dc4b6Seschrock */ 859ea8dc4b6Seschrock zc->zc_cookie = error; 860fa9e4066Sahrens } else { 861ea8dc4b6Seschrock ret = error; 862fa9e4066Sahrens } 863fa9e4066Sahrens 864ea8dc4b6Seschrock return (ret); 865fa9e4066Sahrens } 866fa9e4066Sahrens 867fa9e4066Sahrens /* 868fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 869fa9e4066Sahrens * user land knows which devices are available and overall pool health. 870fa9e4066Sahrens */ 871fa9e4066Sahrens static int 872fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 873fa9e4066Sahrens { 874fa9e4066Sahrens nvlist_t *tryconfig, *config; 875fa9e4066Sahrens int error; 876fa9e4066Sahrens 877990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 878990b4856Slling &tryconfig)) != 0) 879fa9e4066Sahrens return (error); 880fa9e4066Sahrens 881fa9e4066Sahrens config = spa_tryimport(tryconfig); 882fa9e4066Sahrens 883fa9e4066Sahrens nvlist_free(tryconfig); 884fa9e4066Sahrens 885fa9e4066Sahrens if (config == NULL) 886fa9e4066Sahrens return (EINVAL); 887fa9e4066Sahrens 888e9dbad6fSeschrock error = put_nvlist(zc, config); 889fa9e4066Sahrens nvlist_free(config); 890fa9e4066Sahrens 891fa9e4066Sahrens return (error); 892fa9e4066Sahrens } 893fa9e4066Sahrens 894fa9e4066Sahrens static int 895fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 896fa9e4066Sahrens { 897fa9e4066Sahrens spa_t *spa; 898fa9e4066Sahrens int error; 899fa9e4066Sahrens 90006eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 90106eeb2adSek return (error); 90206eeb2adSek 903bb8b5132Sek mutex_enter(&spa_namespace_lock); 90406eeb2adSek error = spa_scrub(spa, zc->zc_cookie, B_FALSE); 905bb8b5132Sek mutex_exit(&spa_namespace_lock); 90606eeb2adSek 90706eeb2adSek spa_close(spa, FTAG); 90806eeb2adSek 909fa9e4066Sahrens return (error); 910fa9e4066Sahrens } 911fa9e4066Sahrens 912fa9e4066Sahrens static int 913fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 914fa9e4066Sahrens { 915fa9e4066Sahrens spa_t *spa; 916fa9e4066Sahrens int error; 917fa9e4066Sahrens 918fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 919fa9e4066Sahrens if (error == 0) { 920fa9e4066Sahrens spa_freeze(spa); 921fa9e4066Sahrens spa_close(spa, FTAG); 922fa9e4066Sahrens } 923fa9e4066Sahrens return (error); 924fa9e4066Sahrens } 925fa9e4066Sahrens 926eaca9bbdSeschrock static int 927eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 928eaca9bbdSeschrock { 929eaca9bbdSeschrock spa_t *spa; 930eaca9bbdSeschrock int error; 931eaca9bbdSeschrock 93206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 93306eeb2adSek return (error); 93406eeb2adSek 935558d2d50Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 936558d2d50Slling spa_close(spa, FTAG); 937558d2d50Slling return (EINVAL); 938558d2d50Slling } 939558d2d50Slling 940990b4856Slling spa_upgrade(spa, zc->zc_cookie); 94106eeb2adSek spa_close(spa, FTAG); 94206eeb2adSek 94306eeb2adSek return (error); 94406eeb2adSek } 94506eeb2adSek 94606eeb2adSek static int 94706eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 94806eeb2adSek { 94906eeb2adSek spa_t *spa; 95006eeb2adSek char *hist_buf; 95106eeb2adSek uint64_t size; 95206eeb2adSek int error; 95306eeb2adSek 95406eeb2adSek if ((size = zc->zc_history_len) == 0) 95506eeb2adSek return (EINVAL); 95606eeb2adSek 95706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 95806eeb2adSek return (error); 95906eeb2adSek 960e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 961d7306b64Sek spa_close(spa, FTAG); 962d7306b64Sek return (ENOTSUP); 963d7306b64Sek } 964d7306b64Sek 96506eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 96606eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 96706eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 968ecd6cf80Smarks error = xcopyout(hist_buf, 969ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 97006eeb2adSek zc->zc_history_len); 97106eeb2adSek } 97206eeb2adSek 97306eeb2adSek spa_close(spa, FTAG); 97406eeb2adSek kmem_free(hist_buf, size); 97506eeb2adSek return (error); 97606eeb2adSek } 97706eeb2adSek 97855434c77Sek static int 97955434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 98055434c77Sek { 98155434c77Sek int error; 98255434c77Sek 983b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 98455434c77Sek return (error); 98555434c77Sek 98655434c77Sek return (0); 98755434c77Sek } 98855434c77Sek 98955434c77Sek static int 99055434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 99155434c77Sek { 99255434c77Sek objset_t *osp; 99355434c77Sek int error; 99455434c77Sek 99555434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 996745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &osp)) != 0) 99755434c77Sek return (error); 99855434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 99955434c77Sek sizeof (zc->zc_value)); 100055434c77Sek dmu_objset_close(osp); 100155434c77Sek 100255434c77Sek return (error); 100355434c77Sek } 100455434c77Sek 1005fa9e4066Sahrens static int 1006fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1007fa9e4066Sahrens { 1008fa9e4066Sahrens spa_t *spa; 1009fa9e4066Sahrens int error; 1010e7cbe64fSgw nvlist_t *config, **l2cache, **spares; 1011e7cbe64fSgw uint_t nl2cache = 0, nspares = 0; 1012fa9e4066Sahrens 1013fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1014fa9e4066Sahrens if (error != 0) 1015fa9e4066Sahrens return (error); 1016fa9e4066Sahrens 1017fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1018fa94a07fSbrendan &config); 1019fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1020fa94a07fSbrendan &l2cache, &nl2cache); 1021fa94a07fSbrendan 1022e7cbe64fSgw (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1023e7cbe64fSgw &spares, &nspares); 1024e7cbe64fSgw 1025b1b8ab34Slling /* 1026b1b8ab34Slling * A root pool with concatenated devices is not supported. 1027e7cbe64fSgw * Thus, can not add a device to a root pool. 1028e7cbe64fSgw * 1029e7cbe64fSgw * Intent log device can not be added to a rootpool because 1030e7cbe64fSgw * during mountroot, zil is replayed, a seperated log device 1031e7cbe64fSgw * can not be accessed during the mountroot time. 1032e7cbe64fSgw * 1033e7cbe64fSgw * l2cache and spare devices are ok to be added to a rootpool. 1034b1b8ab34Slling */ 1035e7cbe64fSgw if (spa->spa_bootfs != 0 && nl2cache == 0 && nspares == 0) { 1036b1b8ab34Slling spa_close(spa, FTAG); 1037b1b8ab34Slling return (EDOM); 1038b1b8ab34Slling } 1039b1b8ab34Slling 1040fa94a07fSbrendan if (error == 0) { 1041fa9e4066Sahrens error = spa_vdev_add(spa, config); 1042fa9e4066Sahrens nvlist_free(config); 1043fa9e4066Sahrens } 1044fa9e4066Sahrens spa_close(spa, FTAG); 1045fa9e4066Sahrens return (error); 1046fa9e4066Sahrens } 1047fa9e4066Sahrens 1048fa9e4066Sahrens static int 1049fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1050fa9e4066Sahrens { 105199653d4eSeschrock spa_t *spa; 105299653d4eSeschrock int error; 105399653d4eSeschrock 105499653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 105599653d4eSeschrock if (error != 0) 105699653d4eSeschrock return (error); 105799653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 105899653d4eSeschrock spa_close(spa, FTAG); 105999653d4eSeschrock return (error); 1060fa9e4066Sahrens } 1061fa9e4066Sahrens 1062fa9e4066Sahrens static int 10633d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1064fa9e4066Sahrens { 1065fa9e4066Sahrens spa_t *spa; 1066fa9e4066Sahrens int error; 10673d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1068fa9e4066Sahrens 106906eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1070fa9e4066Sahrens return (error); 10713d7072f8Seschrock switch (zc->zc_cookie) { 10723d7072f8Seschrock case VDEV_STATE_ONLINE: 10733d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 10743d7072f8Seschrock break; 1075fa9e4066Sahrens 10763d7072f8Seschrock case VDEV_STATE_OFFLINE: 10773d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 10783d7072f8Seschrock break; 1079fa9e4066Sahrens 10803d7072f8Seschrock case VDEV_STATE_FAULTED: 10813d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 10823d7072f8Seschrock break; 10833d7072f8Seschrock 10843d7072f8Seschrock case VDEV_STATE_DEGRADED: 10853d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 10863d7072f8Seschrock break; 10873d7072f8Seschrock 10883d7072f8Seschrock default: 10893d7072f8Seschrock error = EINVAL; 10903d7072f8Seschrock } 10913d7072f8Seschrock zc->zc_cookie = newstate; 1092fa9e4066Sahrens spa_close(spa, FTAG); 1093fa9e4066Sahrens return (error); 1094fa9e4066Sahrens } 1095fa9e4066Sahrens 1096fa9e4066Sahrens static int 1097fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1098fa9e4066Sahrens { 1099fa9e4066Sahrens spa_t *spa; 1100fa9e4066Sahrens int replacing = zc->zc_cookie; 1101fa9e4066Sahrens nvlist_t *config; 1102fa9e4066Sahrens int error; 1103fa9e4066Sahrens 110406eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1105fa9e4066Sahrens return (error); 1106fa9e4066Sahrens 1107990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1108990b4856Slling &config)) == 0) { 1109ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1110fa9e4066Sahrens nvlist_free(config); 1111fa9e4066Sahrens } 1112fa9e4066Sahrens 1113fa9e4066Sahrens spa_close(spa, FTAG); 1114fa9e4066Sahrens return (error); 1115fa9e4066Sahrens } 1116fa9e4066Sahrens 1117fa9e4066Sahrens static int 1118fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1119fa9e4066Sahrens { 1120fa9e4066Sahrens spa_t *spa; 1121fa9e4066Sahrens int error; 1122fa9e4066Sahrens 112306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1124fa9e4066Sahrens return (error); 1125fa9e4066Sahrens 1126ea8dc4b6Seschrock error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 1127fa9e4066Sahrens 1128fa9e4066Sahrens spa_close(spa, FTAG); 1129fa9e4066Sahrens return (error); 1130fa9e4066Sahrens } 1131fa9e4066Sahrens 1132c67d9675Seschrock static int 1133c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1134c67d9675Seschrock { 1135c67d9675Seschrock spa_t *spa; 1136e9dbad6fSeschrock char *path = zc->zc_value; 1137ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1138c67d9675Seschrock int error; 1139c67d9675Seschrock 1140c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1141c67d9675Seschrock if (error != 0) 1142c67d9675Seschrock return (error); 1143c67d9675Seschrock 1144c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1145c67d9675Seschrock spa_close(spa, FTAG); 1146c67d9675Seschrock return (error); 1147c67d9675Seschrock } 1148c67d9675Seschrock 11493cb34c60Sahrens /* 11503cb34c60Sahrens * inputs: 11513cb34c60Sahrens * zc_name name of filesystem 11523cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 11533cb34c60Sahrens * 11543cb34c60Sahrens * outputs: 11553cb34c60Sahrens * zc_objset_stats stats 11563cb34c60Sahrens * zc_nvlist_dst property nvlist 11573cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 11583cb34c60Sahrens */ 1159fa9e4066Sahrens static int 1160fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1161fa9e4066Sahrens { 1162fa9e4066Sahrens objset_t *os = NULL; 1163fa9e4066Sahrens int error; 11647f7322feSeschrock nvlist_t *nv; 1165fa9e4066Sahrens 1166745cd3c5Smaybee if (error = dmu_objset_open(zc->zc_name, 1167745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1168fa9e4066Sahrens return (error); 1169fa9e4066Sahrens 1170a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1171fa9e4066Sahrens 11725ad82045Snd if (zc->zc_nvlist_dst != 0 && 1173745cd3c5Smaybee (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 1174a2eea2e1Sahrens dmu_objset_stats(os, nv); 1175432f72fdSahrens /* 1176bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 1177432f72fdSahrens * which we aren't supposed to do with a 1178745cd3c5Smaybee * DS_MODE_USER hold, because it could be 1179432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1180432f72fdSahrens */ 1181e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1182e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1183e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1184e7437265Sahrens } 1185e9dbad6fSeschrock error = put_nvlist(zc, nv); 11867f7322feSeschrock nvlist_free(nv); 11877f7322feSeschrock } 1188fa9e4066Sahrens 1189fa9e4066Sahrens dmu_objset_close(os); 1190fa9e4066Sahrens return (error); 1191fa9e4066Sahrens } 1192fa9e4066Sahrens 1193de8267e0Stimh static int 1194de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1195de8267e0Stimh { 1196de8267e0Stimh uint64_t value; 1197de8267e0Stimh int error; 1198de8267e0Stimh 1199de8267e0Stimh /* 1200de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 1201de8267e0Stimh * the default value (if there is one). 1202de8267e0Stimh */ 1203de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1204de8267e0Stimh return (error); 1205de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1206de8267e0Stimh return (0); 1207de8267e0Stimh } 1208de8267e0Stimh 12093cb34c60Sahrens /* 12103cb34c60Sahrens * inputs: 12113cb34c60Sahrens * zc_name name of filesystem 1212de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 12133cb34c60Sahrens * 12143cb34c60Sahrens * outputs: 1215de8267e0Stimh * zc_nvlist_dst zpl property nvlist 1216de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 12173cb34c60Sahrens */ 1218bd00f61bSrm static int 1219de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1220bd00f61bSrm { 1221de8267e0Stimh objset_t *os; 1222de8267e0Stimh int err; 1223bd00f61bSrm 1224745cd3c5Smaybee if (err = dmu_objset_open(zc->zc_name, 1225745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1226de8267e0Stimh return (err); 1227bd00f61bSrm 1228bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1229bd00f61bSrm 1230bd00f61bSrm /* 1231de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 1232745cd3c5Smaybee * which we aren't supposed to do with a DS_MODE_USER 1233745cd3c5Smaybee * hold, because it could be inconsistent. 1234bd00f61bSrm */ 1235de8267e0Stimh if (zc->zc_nvlist_dst != NULL && 1236de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 1237de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 1238de8267e0Stimh nvlist_t *nv; 1239de8267e0Stimh 1240de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1241de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1242de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1243de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1244de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1245de8267e0Stimh err = put_nvlist(zc, nv); 1246de8267e0Stimh nvlist_free(nv); 1247de8267e0Stimh } else { 1248de8267e0Stimh err = ENOENT; 1249de8267e0Stimh } 1250bd00f61bSrm dmu_objset_close(os); 1251de8267e0Stimh return (err); 1252bd00f61bSrm } 1253bd00f61bSrm 1254de8267e0Stimh /* 1255de8267e0Stimh * inputs: 1256de8267e0Stimh * zc_name name of filesystem 1257de8267e0Stimh * zc_cookie zap cursor 1258de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 1259de8267e0Stimh * 1260de8267e0Stimh * outputs: 1261de8267e0Stimh * zc_name name of next filesystem 1262de8267e0Stimh * zc_objset_stats stats 1263de8267e0Stimh * zc_nvlist_dst property nvlist 1264de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 1265de8267e0Stimh */ 1266fa9e4066Sahrens static int 1267fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1268fa9e4066Sahrens { 126987e5029aSahrens objset_t *os; 1270fa9e4066Sahrens int error; 1271fa9e4066Sahrens char *p; 1272fa9e4066Sahrens 1273745cd3c5Smaybee if (error = dmu_objset_open(zc->zc_name, 1274745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) { 127587e5029aSahrens if (error == ENOENT) 127687e5029aSahrens error = ESRCH; 127787e5029aSahrens return (error); 1278fa9e4066Sahrens } 1279fa9e4066Sahrens 1280fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1281fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1282fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1283fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1284fa9e4066Sahrens 1285fa9e4066Sahrens do { 128687e5029aSahrens error = dmu_dir_list_next(os, 128787e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 128887e5029aSahrens NULL, &zc->zc_cookie); 1289fa9e4066Sahrens if (error == ENOENT) 1290fa9e4066Sahrens error = ESRCH; 129187e5029aSahrens } while (error == 0 && !INGLOBALZONE(curproc) && 1292fa9e4066Sahrens !zone_dataset_visible(zc->zc_name, NULL)); 1293745cd3c5Smaybee dmu_objset_close(os); 1294fa9e4066Sahrens 1295fa9e4066Sahrens /* 129687e5029aSahrens * If it's a hidden dataset (ie. with a '$' in its name), don't 129787e5029aSahrens * try to get stats for it. Userland will skip over it. 1298fa9e4066Sahrens */ 129987e5029aSahrens if (error == 0 && strchr(zc->zc_name, '$') == NULL) 130087e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1301fa9e4066Sahrens 1302fa9e4066Sahrens return (error); 1303fa9e4066Sahrens } 1304fa9e4066Sahrens 13053cb34c60Sahrens /* 13063cb34c60Sahrens * inputs: 13073cb34c60Sahrens * zc_name name of filesystem 13083cb34c60Sahrens * zc_cookie zap cursor 13093cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13103cb34c60Sahrens * 13113cb34c60Sahrens * outputs: 13123cb34c60Sahrens * zc_name name of next snapshot 13133cb34c60Sahrens * zc_objset_stats stats 13143cb34c60Sahrens * zc_nvlist_dst property nvlist 13153cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 13163cb34c60Sahrens */ 1317fa9e4066Sahrens static int 1318fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1319fa9e4066Sahrens { 132087e5029aSahrens objset_t *os; 1321fa9e4066Sahrens int error; 1322fa9e4066Sahrens 1323745cd3c5Smaybee error = dmu_objset_open(zc->zc_name, 1324745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os); 1325745cd3c5Smaybee if (error) 1326745cd3c5Smaybee return (error == ENOENT ? ESRCH : error); 1327fa9e4066Sahrens 1328b81d61a6Slling /* 1329b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1330b81d61a6Slling * so exit immediately. 1331b81d61a6Slling */ 1332b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 133387e5029aSahrens dmu_objset_close(os); 1334b81d61a6Slling return (ESRCH); 1335fa9e4066Sahrens } 1336fa9e4066Sahrens 133787e5029aSahrens error = dmu_snapshot_list_next(os, 133887e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 1339b38f0970Sck zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 1340745cd3c5Smaybee dmu_objset_close(os); 134187e5029aSahrens if (error == 0) 134287e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1343745cd3c5Smaybee else if (error == ENOENT) 1344745cd3c5Smaybee error = ESRCH; 1345fa9e4066Sahrens 13463cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 1347745cd3c5Smaybee if (error) 13483cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 1349fa9e4066Sahrens return (error); 1350fa9e4066Sahrens } 1351fa9e4066Sahrens 1352e7cbe64fSgw int 135391ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1354fa9e4066Sahrens { 1355e9dbad6fSeschrock nvpair_t *elem; 1356e9dbad6fSeschrock int error; 1357e9dbad6fSeschrock uint64_t intval; 1358e9dbad6fSeschrock char *strval; 1359e9dbad6fSeschrock 1360ecd6cf80Smarks /* 1361ecd6cf80Smarks * First validate permission to set all of the properties 1362ecd6cf80Smarks */ 1363e9dbad6fSeschrock elem = NULL; 1364e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1365db870a07Sahrens const char *propname = nvpair_name(elem); 1366db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1367e9dbad6fSeschrock 1368990b4856Slling if (prop == ZPROP_INVAL) { 1369e9dbad6fSeschrock /* 1370e9dbad6fSeschrock * If this is a user-defined property, it must be a 1371e9dbad6fSeschrock * string, and there is no further validation to do. 1372e9dbad6fSeschrock */ 1373e9dbad6fSeschrock if (!zfs_prop_user(propname) || 1374e9dbad6fSeschrock nvpair_type(elem) != DATA_TYPE_STRING) 1375e9dbad6fSeschrock return (EINVAL); 1376e9dbad6fSeschrock 1377da6c28aaSamw if (error = zfs_secpolicy_write_perms(name, 1378da6c28aaSamw ZFS_DELEG_PERM_USERPROP, CRED())) 1379db870a07Sahrens return (error); 1380ecd6cf80Smarks continue; 1381e9dbad6fSeschrock } 1382fa9e4066Sahrens 138391ebeef5Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1384db870a07Sahrens return (error); 1385db870a07Sahrens 1386e9dbad6fSeschrock /* 1387db870a07Sahrens * Check that this value is valid for this pool version 1388e9dbad6fSeschrock */ 1389e9dbad6fSeschrock switch (prop) { 1390c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1391c9431fa1Sahl /* 1392c9431fa1Sahl * If the user specified gzip compression, make sure 1393c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1394c9431fa1Sahl * we'll catch them later. 1395c9431fa1Sahl */ 1396c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1397*15e6edf1Sgw nvpair_value_uint64(elem, &intval) == 0) { 1398*15e6edf1Sgw if (intval >= ZIO_COMPRESS_GZIP_1 && 1399*15e6edf1Sgw intval <= ZIO_COMPRESS_GZIP_9 && 1400*15e6edf1Sgw zfs_check_version(name, 1401da6c28aaSamw SPA_VERSION_GZIP_COMPRESSION)) 1402da6c28aaSamw return (ENOTSUP); 1403*15e6edf1Sgw 1404*15e6edf1Sgw /* 1405*15e6edf1Sgw * If this is a bootable dataset then 1406*15e6edf1Sgw * verify that the compression algorithm 1407*15e6edf1Sgw * is supported for booting. We must return 1408*15e6edf1Sgw * something other than ENOTSUP since it 1409*15e6edf1Sgw * implies a downrev pool version. 1410*15e6edf1Sgw */ 1411*15e6edf1Sgw if (zfs_is_bootfs(name) && 1412*15e6edf1Sgw !BOOTFS_COMPRESS_VALID(intval)) 1413*15e6edf1Sgw return (ERANGE); 1414c9431fa1Sahl } 1415c9431fa1Sahl break; 141640feaa91Sahrens 141740feaa91Sahrens case ZFS_PROP_COPIES: 1418da6c28aaSamw if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS)) 1419da6c28aaSamw return (ENOTSUP); 142040feaa91Sahrens break; 14219e6eda55Smarks 14229e6eda55Smarks case ZFS_PROP_SHARESMB: 1423745cd3c5Smaybee if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 14249e6eda55Smarks return (ENOTSUP); 14259e6eda55Smarks break; 142640feaa91Sahrens } 1427da6c28aaSamw if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1428da6c28aaSamw return (error); 1429ecd6cf80Smarks } 1430ecd6cf80Smarks 1431ecd6cf80Smarks elem = NULL; 1432ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1433db870a07Sahrens const char *propname = nvpair_name(elem); 1434db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1435ecd6cf80Smarks 1436990b4856Slling if (prop == ZPROP_INVAL) { 1437ecd6cf80Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 1438ecd6cf80Smarks error = dsl_prop_set(name, propname, 1, 1439ecd6cf80Smarks strlen(strval) + 1, strval); 1440ecd6cf80Smarks if (error == 0) 1441ecd6cf80Smarks continue; 1442ecd6cf80Smarks else 1443ecd6cf80Smarks return (error); 1444ecd6cf80Smarks } 1445e9dbad6fSeschrock 1446e9dbad6fSeschrock switch (prop) { 1447e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1448e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1449e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 1450e9dbad6fSeschrock return (error); 1451e9dbad6fSeschrock break; 1452e9dbad6fSeschrock 1453a9799022Sck case ZFS_PROP_REFQUOTA: 1454a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1455a9799022Sck (error = dsl_dataset_set_quota(name, intval)) != 0) 1456a9799022Sck return (error); 1457a9799022Sck break; 1458a9799022Sck 1459e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1460e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1461e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1462e9dbad6fSeschrock intval)) != 0) 1463e9dbad6fSeschrock return (error); 1464e9dbad6fSeschrock break; 1465e9dbad6fSeschrock 1466a9799022Sck case ZFS_PROP_REFRESERVATION: 1467a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1468a9799022Sck (error = dsl_dataset_set_reservation(name, 1469a9799022Sck intval)) != 0) 1470a9799022Sck return (error); 1471a9799022Sck break; 1472a9799022Sck 1473e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1474e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 147591ebeef5Sahrens (error = zvol_set_volsize(name, 147691ebeef5Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 1477e9dbad6fSeschrock return (error); 1478e9dbad6fSeschrock break; 1479e9dbad6fSeschrock 1480e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1481e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1482e7437265Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 1483e7437265Sahrens return (error); 1484e7437265Sahrens break; 1485e7437265Sahrens 1486e7437265Sahrens case ZFS_PROP_VERSION: 1487e7437265Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1488e7437265Sahrens (error = zfs_set_version(name, intval)) != 0) 1489e9dbad6fSeschrock return (error); 1490e9dbad6fSeschrock break; 1491e9dbad6fSeschrock 1492e9dbad6fSeschrock default: 1493e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1494e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 149591ebeef5Sahrens PROP_TYPE_STRING) 1496e9dbad6fSeschrock return (EINVAL); 1497acd76fe5Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 1498acd76fe5Seschrock if ((error = dsl_prop_set(name, 1499e9dbad6fSeschrock nvpair_name(elem), 1, strlen(strval) + 1, 1500acd76fe5Seschrock strval)) != 0) 1501acd76fe5Seschrock return (error); 1502e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1503a2eea2e1Sahrens const char *unused; 1504a2eea2e1Sahrens 1505acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1506e9dbad6fSeschrock 1507e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 150891ebeef5Sahrens case PROP_TYPE_NUMBER: 1509e9dbad6fSeschrock break; 151091ebeef5Sahrens case PROP_TYPE_STRING: 1511acd76fe5Seschrock return (EINVAL); 151291ebeef5Sahrens case PROP_TYPE_INDEX: 1513acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 1514acd76fe5Seschrock intval, &unused) != 0) 1515acd76fe5Seschrock return (EINVAL); 1516e9dbad6fSeschrock break; 1517e9dbad6fSeschrock default: 1518e7437265Sahrens cmn_err(CE_PANIC, 1519e7437265Sahrens "unknown property type"); 1520e9dbad6fSeschrock break; 1521e9dbad6fSeschrock } 1522e9dbad6fSeschrock 1523acd76fe5Seschrock if ((error = dsl_prop_set(name, propname, 1524acd76fe5Seschrock 8, 1, &intval)) != 0) 1525acd76fe5Seschrock return (error); 1526e9dbad6fSeschrock } else { 1527e9dbad6fSeschrock return (EINVAL); 1528e9dbad6fSeschrock } 1529e9dbad6fSeschrock break; 1530e9dbad6fSeschrock } 1531e9dbad6fSeschrock } 1532e9dbad6fSeschrock 1533e9dbad6fSeschrock return (0); 1534fa9e4066Sahrens } 1535fa9e4066Sahrens 15363cb34c60Sahrens /* 15373cb34c60Sahrens * inputs: 15383cb34c60Sahrens * zc_name name of filesystem 15393cb34c60Sahrens * zc_value name of property to inherit 15403cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 15413cb34c60Sahrens * 15423cb34c60Sahrens * outputs: none 15433cb34c60Sahrens */ 1544fa9e4066Sahrens static int 1545e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1546fa9e4066Sahrens { 1547e9dbad6fSeschrock nvlist_t *nvl; 1548e9dbad6fSeschrock int error; 1549e9dbad6fSeschrock 1550990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1551990b4856Slling &nvl)) != 0) 1552e9dbad6fSeschrock return (error); 1553e9dbad6fSeschrock 155491ebeef5Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1555ecd6cf80Smarks 1556e9dbad6fSeschrock nvlist_free(nvl); 1557e9dbad6fSeschrock return (error); 1558fa9e4066Sahrens } 1559fa9e4066Sahrens 15603cb34c60Sahrens /* 15613cb34c60Sahrens * inputs: 15623cb34c60Sahrens * zc_name name of filesystem 15633cb34c60Sahrens * zc_value name of property to inherit 15643cb34c60Sahrens * 15653cb34c60Sahrens * outputs: none 15663cb34c60Sahrens */ 1567e45ce728Sahrens static int 1568e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 1569e45ce728Sahrens { 1570e45ce728Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 1571e45ce728Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1572e45ce728Sahrens } 1573e45ce728Sahrens 1574b1b8ab34Slling static int 157511a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1576b1b8ab34Slling { 1577990b4856Slling nvlist_t *props; 1578b1b8ab34Slling spa_t *spa; 1579990b4856Slling int error; 1580b1b8ab34Slling 1581990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1582990b4856Slling &props))) 1583b1b8ab34Slling return (error); 1584b1b8ab34Slling 1585b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1586990b4856Slling nvlist_free(props); 1587b1b8ab34Slling return (error); 1588b1b8ab34Slling } 1589b1b8ab34Slling 1590990b4856Slling error = spa_prop_set(spa, props); 1591b1b8ab34Slling 1592990b4856Slling nvlist_free(props); 1593b1b8ab34Slling spa_close(spa, FTAG); 1594b1b8ab34Slling 1595b1b8ab34Slling return (error); 1596b1b8ab34Slling } 1597b1b8ab34Slling 1598b1b8ab34Slling static int 159911a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1600b1b8ab34Slling { 1601b1b8ab34Slling spa_t *spa; 1602b1b8ab34Slling int error; 1603b1b8ab34Slling nvlist_t *nvp = NULL; 1604b1b8ab34Slling 1605b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1606b1b8ab34Slling return (error); 1607b1b8ab34Slling 1608990b4856Slling error = spa_prop_get(spa, &nvp); 1609b1b8ab34Slling 1610b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1611b1b8ab34Slling error = put_nvlist(zc, nvp); 1612b1b8ab34Slling else 1613b1b8ab34Slling error = EFAULT; 1614b1b8ab34Slling 1615b1b8ab34Slling spa_close(spa, FTAG); 1616b1b8ab34Slling 1617b1b8ab34Slling if (nvp) 1618b1b8ab34Slling nvlist_free(nvp); 1619b1b8ab34Slling return (error); 1620b1b8ab34Slling } 1621b1b8ab34Slling 1622ecd6cf80Smarks static int 1623ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1624ecd6cf80Smarks { 1625ecd6cf80Smarks nvlist_t *nvp; 1626ecd6cf80Smarks int error; 1627ecd6cf80Smarks uint32_t uid; 1628ecd6cf80Smarks uint32_t gid; 1629ecd6cf80Smarks uint32_t *groups; 1630ecd6cf80Smarks uint_t group_cnt; 1631ecd6cf80Smarks cred_t *usercred; 1632ecd6cf80Smarks 1633990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1634990b4856Slling &nvp)) != 0) { 1635ecd6cf80Smarks return (error); 1636ecd6cf80Smarks } 1637ecd6cf80Smarks 1638ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1639ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 1640ecd6cf80Smarks nvlist_free(nvp); 1641ecd6cf80Smarks return (EPERM); 1642ecd6cf80Smarks } 1643ecd6cf80Smarks 1644ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1645ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 1646ecd6cf80Smarks nvlist_free(nvp); 1647ecd6cf80Smarks return (EPERM); 1648ecd6cf80Smarks } 1649ecd6cf80Smarks 1650ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1651ecd6cf80Smarks &groups, &group_cnt)) != 0) { 1652ecd6cf80Smarks nvlist_free(nvp); 1653ecd6cf80Smarks return (EPERM); 1654ecd6cf80Smarks } 1655ecd6cf80Smarks usercred = cralloc(); 1656ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 1657ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1658ecd6cf80Smarks nvlist_free(nvp); 1659ecd6cf80Smarks crfree(usercred); 1660ecd6cf80Smarks return (EPERM); 1661ecd6cf80Smarks } 1662ecd6cf80Smarks nvlist_free(nvp); 1663ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 166491ebeef5Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 1665ecd6cf80Smarks crfree(usercred); 1666ecd6cf80Smarks return (error); 1667ecd6cf80Smarks } 1668ecd6cf80Smarks 16693cb34c60Sahrens /* 16703cb34c60Sahrens * inputs: 16713cb34c60Sahrens * zc_name name of filesystem 16723cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 16733cb34c60Sahrens * zc_perm_action allow/unallow flag 16743cb34c60Sahrens * 16753cb34c60Sahrens * outputs: none 16763cb34c60Sahrens */ 1677ecd6cf80Smarks static int 1678ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 1679ecd6cf80Smarks { 1680ecd6cf80Smarks int error; 1681ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 1682ecd6cf80Smarks 1683990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1684990b4856Slling &fsaclnv)) != 0) 1685ecd6cf80Smarks return (error); 1686ecd6cf80Smarks 1687ecd6cf80Smarks /* 1688ecd6cf80Smarks * Verify nvlist is constructed correctly 1689ecd6cf80Smarks */ 1690ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1691ecd6cf80Smarks nvlist_free(fsaclnv); 1692ecd6cf80Smarks return (EINVAL); 1693ecd6cf80Smarks } 1694ecd6cf80Smarks 1695ecd6cf80Smarks /* 1696ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 1697ecd6cf80Smarks * that user is allowed to hand out each permission in 1698ecd6cf80Smarks * the nvlist(s) 1699ecd6cf80Smarks */ 1700ecd6cf80Smarks 170191ebeef5Sahrens error = secpolicy_zfs(CRED()); 1702ecd6cf80Smarks if (error) { 170391ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 170491ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 170591ebeef5Sahrens fsaclnv, CRED()); 170691ebeef5Sahrens } else { 170791ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 170891ebeef5Sahrens fsaclnv, CRED()); 170991ebeef5Sahrens } 1710ecd6cf80Smarks } 1711ecd6cf80Smarks 1712ecd6cf80Smarks if (error == 0) 1713ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1714ecd6cf80Smarks 1715ecd6cf80Smarks nvlist_free(fsaclnv); 1716ecd6cf80Smarks return (error); 1717ecd6cf80Smarks } 1718ecd6cf80Smarks 17193cb34c60Sahrens /* 17203cb34c60Sahrens * inputs: 17213cb34c60Sahrens * zc_name name of filesystem 17223cb34c60Sahrens * 17233cb34c60Sahrens * outputs: 17243cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 17253cb34c60Sahrens */ 1726ecd6cf80Smarks static int 1727ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 1728ecd6cf80Smarks { 1729ecd6cf80Smarks nvlist_t *nvp; 1730ecd6cf80Smarks int error; 1731ecd6cf80Smarks 1732ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1733ecd6cf80Smarks error = put_nvlist(zc, nvp); 1734ecd6cf80Smarks nvlist_free(nvp); 1735ecd6cf80Smarks } 1736ecd6cf80Smarks 1737ecd6cf80Smarks return (error); 1738ecd6cf80Smarks } 1739ecd6cf80Smarks 17403cb34c60Sahrens /* 17413cb34c60Sahrens * inputs: 17423cb34c60Sahrens * zc_name name of volume 17433cb34c60Sahrens * 17443cb34c60Sahrens * outputs: none 17453cb34c60Sahrens */ 1746fa9e4066Sahrens static int 1747fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1748fa9e4066Sahrens { 174991ebeef5Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1750fa9e4066Sahrens } 1751fa9e4066Sahrens 17523cb34c60Sahrens /* 17533cb34c60Sahrens * inputs: 17543cb34c60Sahrens * zc_name name of volume 17553cb34c60Sahrens * 17563cb34c60Sahrens * outputs: none 17573cb34c60Sahrens */ 1758fa9e4066Sahrens static int 1759fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1760fa9e4066Sahrens { 1761e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 1762fa9e4066Sahrens } 1763fa9e4066Sahrens 1764fa9e4066Sahrens /* 1765fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1766fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 1767fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 1768fa9e4066Sahrens */ 1769fa9e4066Sahrens static vfs_t * 1770fa9e4066Sahrens zfs_get_vfs(const char *resource) 1771fa9e4066Sahrens { 1772fa9e4066Sahrens struct vfs *vfsp; 1773fa9e4066Sahrens struct vfs *vfs_found = NULL; 1774fa9e4066Sahrens 1775fa9e4066Sahrens vfs_list_read_lock(); 1776fa9e4066Sahrens vfsp = rootvfs; 1777fa9e4066Sahrens do { 1778fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1779fa9e4066Sahrens VFS_HOLD(vfsp); 1780fa9e4066Sahrens vfs_found = vfsp; 1781fa9e4066Sahrens break; 1782fa9e4066Sahrens } 1783fa9e4066Sahrens vfsp = vfsp->vfs_next; 1784fa9e4066Sahrens } while (vfsp != rootvfs); 1785fa9e4066Sahrens vfs_list_unlock(); 1786fa9e4066Sahrens return (vfs_found); 1787fa9e4066Sahrens } 1788fa9e4066Sahrens 1789ecd6cf80Smarks /* ARGSUSED */ 1790fa9e4066Sahrens static void 1791ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1792fa9e4066Sahrens { 1793da6c28aaSamw zfs_creat_t *zct = arg; 1794da6c28aaSamw 1795de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 1796da6c28aaSamw } 1797da6c28aaSamw 1798de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 1799da6c28aaSamw 1800da6c28aaSamw /* 1801de8267e0Stimh * inputs: 1802de8267e0Stimh * createprops list of properties requested by creator 1803de8267e0Stimh * dataset name of dataset we are creating 1804de8267e0Stimh * 1805de8267e0Stimh * outputs: 1806de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 1807da6c28aaSamw * 1808de8267e0Stimh * Determine the settings for utf8only, normalization and 1809de8267e0Stimh * casesensitivity. Specific values may have been requested by the 1810de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 1811de8267e0Stimh * the file system is of too early a vintage, a creator can not 1812de8267e0Stimh * request settings for these properties, even if the requested 1813de8267e0Stimh * setting is the default value. We don't actually want to create dsl 1814de8267e0Stimh * properties for these, so remove them from the source nvlist after 1815de8267e0Stimh * processing. 1816da6c28aaSamw */ 1817da6c28aaSamw static int 1818de8267e0Stimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 1819ab04eb8eStimh nvlist_t *zplprops, uint64_t zplver, boolean_t *is_ci) 1820da6c28aaSamw { 1821de8267e0Stimh objset_t *os; 1822da6c28aaSamw char parentname[MAXNAMELEN]; 1823da6c28aaSamw char *cp; 1824de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 1825de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 1826de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 1827de8267e0Stimh int error = 0; 1828da6c28aaSamw 1829de8267e0Stimh ASSERT(zplprops != NULL); 1830da6c28aaSamw 1831de8267e0Stimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 1832de8267e0Stimh cp = strrchr(parentname, '/'); 1833de8267e0Stimh ASSERT(cp != NULL); 1834de8267e0Stimh cp[0] = '\0'; 1835da6c28aaSamw 1836de8267e0Stimh /* 1837de8267e0Stimh * Pull out creator prop choices, if any. 1838de8267e0Stimh */ 1839de8267e0Stimh if (createprops) { 1840de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1841de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 1842de8267e0Stimh (void) nvlist_remove_all(createprops, 1843de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 1844de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1845de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 1846de8267e0Stimh (void) nvlist_remove_all(createprops, 1847de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1848de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1849de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 1850de8267e0Stimh (void) nvlist_remove_all(createprops, 1851de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 1852de8267e0Stimh } 1853da6c28aaSamw 1854c2a93d44Stimh /* 1855de8267e0Stimh * If the file system or pool is version is too "young" to 1856de8267e0Stimh * support normalization and the creator tried to set a value 1857de8267e0Stimh * for one of the props, error out. We only need check the 1858de8267e0Stimh * ZPL version because we've already checked by now that the 1859de8267e0Stimh * SPA version is compatible with the selected ZPL version. 1860c2a93d44Stimh */ 1861de8267e0Stimh if (zplver < ZPL_VERSION_NORMALIZATION && 1862de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 1863de8267e0Stimh sense != ZFS_PROP_UNDEFINED)) 1864de8267e0Stimh return (ENOTSUP); 1865c2a93d44Stimh 1866de8267e0Stimh /* 1867de8267e0Stimh * Put the version in the zplprops 1868de8267e0Stimh */ 1869de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1870de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 1871da6c28aaSamw 1872de8267e0Stimh /* 1873de8267e0Stimh * Open parent object set so we can inherit zplprop values if 1874de8267e0Stimh * necessary. 1875de8267e0Stimh */ 1876745cd3c5Smaybee if (error = dmu_objset_open(parentname, 1877745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1878da6c28aaSamw return (error); 1879da6c28aaSamw 1880de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 1881de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 1882de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1883de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 1884da6c28aaSamw 1885c2a93d44Stimh /* 1886de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 1887c2a93d44Stimh */ 1888de8267e0Stimh if (norm) 1889de8267e0Stimh u8 = 1; 1890de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 1891de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 1892de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1893de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 1894de8267e0Stimh 1895de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 1896de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 1897de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1898de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 1899c2a93d44Stimh 1900ab04eb8eStimh if (is_ci) 1901ab04eb8eStimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 1902ab04eb8eStimh 1903de8267e0Stimh dmu_objset_close(os); 1904da6c28aaSamw return (0); 1905fa9e4066Sahrens } 1906fa9e4066Sahrens 19073cb34c60Sahrens /* 19083cb34c60Sahrens * inputs: 19093cb34c60Sahrens * zc_objset_type type of objset to create (fs vs zvol) 19103cb34c60Sahrens * zc_name name of new objset 19113cb34c60Sahrens * zc_value name of snapshot to clone from (may be empty) 19123cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 19133cb34c60Sahrens * 1914de8267e0Stimh * outputs: none 19153cb34c60Sahrens */ 1916fa9e4066Sahrens static int 1917fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 1918fa9e4066Sahrens { 1919fa9e4066Sahrens objset_t *clone; 1920fa9e4066Sahrens int error = 0; 1921da6c28aaSamw zfs_creat_t zct; 1922ecd6cf80Smarks nvlist_t *nvprops = NULL; 1923ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 1924fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 1925fa9e4066Sahrens 1926fa9e4066Sahrens switch (type) { 1927fa9e4066Sahrens 1928fa9e4066Sahrens case DMU_OST_ZFS: 1929fa9e4066Sahrens cbfunc = zfs_create_cb; 1930fa9e4066Sahrens break; 1931fa9e4066Sahrens 1932fa9e4066Sahrens case DMU_OST_ZVOL: 1933fa9e4066Sahrens cbfunc = zvol_create_cb; 1934fa9e4066Sahrens break; 1935fa9e4066Sahrens 1936fa9e4066Sahrens default: 19371d452cf5Sahrens cbfunc = NULL; 1938e7cbe64fSgw break; 1939fa9e4066Sahrens } 1940f18faf3fSek if (strchr(zc->zc_name, '@') || 1941f18faf3fSek strchr(zc->zc_name, '%')) 19421d452cf5Sahrens return (EINVAL); 1943fa9e4066Sahrens 1944e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 1945990b4856Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1946990b4856Slling &nvprops)) != 0) 1947e9dbad6fSeschrock return (error); 1948e9dbad6fSeschrock 1949de8267e0Stimh zct.zct_zplprops = NULL; 1950da6c28aaSamw zct.zct_props = nvprops; 1951da6c28aaSamw 1952e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1953fa9e4066Sahrens /* 1954fa9e4066Sahrens * We're creating a clone of an existing snapshot. 1955fa9e4066Sahrens */ 1956e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1957e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 1958ecd6cf80Smarks nvlist_free(nvprops); 1959fa9e4066Sahrens return (EINVAL); 1960e9dbad6fSeschrock } 1961fa9e4066Sahrens 1962e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 1963745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 1964e9dbad6fSeschrock if (error) { 1965ecd6cf80Smarks nvlist_free(nvprops); 1966fa9e4066Sahrens return (error); 1967e9dbad6fSeschrock } 1968ab04eb8eStimh 1969ab04eb8eStimh error = dmu_objset_create(zc->zc_name, type, clone, 0, 1970ab04eb8eStimh NULL, NULL); 1971da6c28aaSamw if (error) { 1972da6c28aaSamw dmu_objset_close(clone); 1973da6c28aaSamw nvlist_free(nvprops); 1974da6c28aaSamw return (error); 1975da6c28aaSamw } 1976fa9e4066Sahrens dmu_objset_close(clone); 1977fa9e4066Sahrens } else { 1978ab04eb8eStimh boolean_t is_insensitive = B_FALSE; 1979ab04eb8eStimh 1980e9dbad6fSeschrock if (cbfunc == NULL) { 1981ecd6cf80Smarks nvlist_free(nvprops); 19821d452cf5Sahrens return (EINVAL); 1983e9dbad6fSeschrock } 19845c5460e9Seschrock 1985e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 1986e9dbad6fSeschrock uint64_t volsize, volblocksize; 1987e9dbad6fSeschrock 1988ecd6cf80Smarks if (nvprops == NULL || 1989ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 1990e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1991e9dbad6fSeschrock &volsize) != 0) { 1992ecd6cf80Smarks nvlist_free(nvprops); 1993e9dbad6fSeschrock return (EINVAL); 1994e9dbad6fSeschrock } 1995e9dbad6fSeschrock 1996ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 1997e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1998e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 1999ecd6cf80Smarks nvlist_free(nvprops); 2000e9dbad6fSeschrock return (EINVAL); 2001e9dbad6fSeschrock } 2002e9dbad6fSeschrock 2003e9dbad6fSeschrock if (error != 0) 2004e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 2005e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 2006e9dbad6fSeschrock 2007e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 2008e9dbad6fSeschrock volblocksize)) != 0 || 2009e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 2010e9dbad6fSeschrock volblocksize)) != 0) { 2011ecd6cf80Smarks nvlist_free(nvprops); 20125c5460e9Seschrock return (error); 2013e9dbad6fSeschrock } 2014e7437265Sahrens } else if (type == DMU_OST_ZFS) { 2015e7437265Sahrens uint64_t version; 2016da6c28aaSamw int error; 2017da6c28aaSamw 2018de8267e0Stimh /* 2019de8267e0Stimh * Default ZPL version to non-FUID capable if the 2020de8267e0Stimh * pool is not upgraded to support FUIDs. 2021de8267e0Stimh */ 2022de8267e0Stimh if (zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) 2023de8267e0Stimh version = ZPL_VERSION_FUID - 1; 2024de8267e0Stimh else 2025de8267e0Stimh version = ZPL_VERSION; 2026de8267e0Stimh 2027de8267e0Stimh /* 2028de8267e0Stimh * Potentially override default ZPL version based 2029de8267e0Stimh * on creator's request. 2030de8267e0Stimh */ 2031de8267e0Stimh (void) nvlist_lookup_uint64(nvprops, 2032da6c28aaSamw zfs_prop_to_name(ZFS_PROP_VERSION), &version); 2033e7437265Sahrens 2034de8267e0Stimh /* 2035de8267e0Stimh * Make sure version we ended up with is kosher 2036de8267e0Stimh */ 2037de8267e0Stimh if ((version < ZPL_VERSION_INITIAL || 2038de8267e0Stimh version > ZPL_VERSION) || 2039de8267e0Stimh (version >= ZPL_VERSION_FUID && 2040de8267e0Stimh zfs_check_version(zc->zc_name, SPA_VERSION_FUID))) { 2041da6c28aaSamw nvlist_free(nvprops); 2042da6c28aaSamw return (ENOTSUP); 2043e7437265Sahrens } 2044e9dbad6fSeschrock 2045da6c28aaSamw /* 2046da6c28aaSamw * We have to have normalization and 2047da6c28aaSamw * case-folding flags correct when we do the 2048da6c28aaSamw * file system creation, so go figure them out 2049de8267e0Stimh * now. 2050da6c28aaSamw */ 2051de8267e0Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 2052de8267e0Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 2053de8267e0Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 2054ab04eb8eStimh zct.zct_zplprops, version, &is_insensitive); 2055da6c28aaSamw if (error != 0) { 2056da6c28aaSamw nvlist_free(nvprops); 2057de8267e0Stimh nvlist_free(zct.zct_zplprops); 2058da6c28aaSamw return (error); 2059da6c28aaSamw } 2060da6c28aaSamw } 2061ab04eb8eStimh error = dmu_objset_create(zc->zc_name, type, NULL, 2062ab04eb8eStimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 2063de8267e0Stimh nvlist_free(zct.zct_zplprops); 2064fa9e4066Sahrens } 2065e9dbad6fSeschrock 2066e9dbad6fSeschrock /* 2067e9dbad6fSeschrock * It would be nice to do this atomically. 2068e9dbad6fSeschrock */ 2069e9dbad6fSeschrock if (error == 0) { 207091ebeef5Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 2071e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 2072e9dbad6fSeschrock } 2073ecd6cf80Smarks nvlist_free(nvprops); 2074fa9e4066Sahrens return (error); 2075fa9e4066Sahrens } 2076fa9e4066Sahrens 20773cb34c60Sahrens /* 20783cb34c60Sahrens * inputs: 20793cb34c60Sahrens * zc_name name of filesystem 20803cb34c60Sahrens * zc_value short name of snapshot 20813cb34c60Sahrens * zc_cookie recursive flag 20823cb34c60Sahrens * 20833cb34c60Sahrens * outputs: none 20843cb34c60Sahrens */ 2085fa9e4066Sahrens static int 20861d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 2087fa9e4066Sahrens { 2088e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 20891d452cf5Sahrens return (EINVAL); 20901d452cf5Sahrens return (dmu_objset_snapshot(zc->zc_name, 2091e9dbad6fSeschrock zc->zc_value, zc->zc_cookie)); 20921d452cf5Sahrens } 2093fa9e4066Sahrens 2094cdf5b4caSmmusante int 20951d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 20961d452cf5Sahrens { 20970b69c2f0Sahrens vfs_t *vfsp = NULL; 20981d452cf5Sahrens 2099745cd3c5Smaybee if (arg) { 2100745cd3c5Smaybee char *snapname = arg; 2101745cd3c5Smaybee int len = strlen(name) + strlen(snapname) + 2; 2102745cd3c5Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 21031d452cf5Sahrens 2104745cd3c5Smaybee (void) strcpy(buf, name); 2105745cd3c5Smaybee (void) strcat(buf, "@"); 2106745cd3c5Smaybee (void) strcat(buf, snapname); 2107745cd3c5Smaybee vfsp = zfs_get_vfs(buf); 2108745cd3c5Smaybee kmem_free(buf, len); 21090b69c2f0Sahrens } else if (strchr(name, '@')) { 21101d452cf5Sahrens vfsp = zfs_get_vfs(name); 21111d452cf5Sahrens } 21121d452cf5Sahrens 21131d452cf5Sahrens if (vfsp) { 2114fa9e4066Sahrens /* 21151d452cf5Sahrens * Always force the unmount for snapshots. 2116fa9e4066Sahrens */ 21171d452cf5Sahrens int flag = MS_FORCE; 21181d452cf5Sahrens int err; 21191d452cf5Sahrens 21201d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 2121fa9e4066Sahrens VFS_RELE(vfsp); 21221d452cf5Sahrens return (err); 2123fa9e4066Sahrens } 21241d452cf5Sahrens VFS_RELE(vfsp); 21251d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 21261d452cf5Sahrens return (err); 21271d452cf5Sahrens } 21281d452cf5Sahrens return (0); 21291d452cf5Sahrens } 21301d452cf5Sahrens 21313cb34c60Sahrens /* 21323cb34c60Sahrens * inputs: 21333cb34c60Sahrens * zc_name name of filesystem 21343cb34c60Sahrens * zc_value short name of snapshot 21353cb34c60Sahrens * 21363cb34c60Sahrens * outputs: none 21373cb34c60Sahrens */ 21381d452cf5Sahrens static int 21391d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 21401d452cf5Sahrens { 21411d452cf5Sahrens int err; 21421d452cf5Sahrens 2143e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 21441d452cf5Sahrens return (EINVAL); 21451d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 2146e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 21471d452cf5Sahrens if (err) 21481d452cf5Sahrens return (err); 2149e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 21501d452cf5Sahrens } 21511d452cf5Sahrens 21523cb34c60Sahrens /* 21533cb34c60Sahrens * inputs: 21543cb34c60Sahrens * zc_name name of dataset to destroy 21553cb34c60Sahrens * zc_objset_type type of objset 21563cb34c60Sahrens * 21573cb34c60Sahrens * outputs: none 21583cb34c60Sahrens */ 21591d452cf5Sahrens static int 21601d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 21611d452cf5Sahrens { 21621d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 21631d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 21641d452cf5Sahrens if (err) 21651d452cf5Sahrens return (err); 2166fa9e4066Sahrens } 2167fa9e4066Sahrens 2168fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 2169fa9e4066Sahrens } 2170fa9e4066Sahrens 21713cb34c60Sahrens /* 21723cb34c60Sahrens * inputs: 21734ccbb6e7Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 21743cb34c60Sahrens * 21753cb34c60Sahrens * outputs: none 21763cb34c60Sahrens */ 2177fa9e4066Sahrens static int 2178fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2179fa9e4066Sahrens { 21804ccbb6e7Sahrens objset_t *os; 21814ccbb6e7Sahrens int error; 21824ccbb6e7Sahrens zfsvfs_t *zfsvfs = NULL; 21834ccbb6e7Sahrens 21844ccbb6e7Sahrens /* 21854ccbb6e7Sahrens * Get the zfsvfs for the receiving objset. There 21864ccbb6e7Sahrens * won't be one if we're operating on a zvol, if the 21874ccbb6e7Sahrens * objset doesn't exist yet, or is not mounted. 21884ccbb6e7Sahrens */ 2189745cd3c5Smaybee error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, DS_MODE_USER, &os); 21904ccbb6e7Sahrens if (error) 21914ccbb6e7Sahrens return (error); 21924ccbb6e7Sahrens 21934ccbb6e7Sahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 21944ccbb6e7Sahrens mutex_enter(&os->os->os_user_ptr_lock); 21954ccbb6e7Sahrens zfsvfs = dmu_objset_get_user(os); 21964ccbb6e7Sahrens if (zfsvfs != NULL) 21974ccbb6e7Sahrens VFS_HOLD(zfsvfs->z_vfs); 21984ccbb6e7Sahrens mutex_exit(&os->os->os_user_ptr_lock); 21994ccbb6e7Sahrens } 22004ccbb6e7Sahrens 22014ccbb6e7Sahrens if (zfsvfs != NULL) { 22024ccbb6e7Sahrens char osname[MAXNAMELEN]; 22034ccbb6e7Sahrens int mode; 22044ccbb6e7Sahrens 220547f263f4Sek error = zfs_suspend_fs(zfsvfs, osname, &mode); 220647f263f4Sek if (error == 0) { 220747f263f4Sek int resume_err; 22084ccbb6e7Sahrens 220947f263f4Sek ASSERT(strcmp(osname, zc->zc_name) == 0); 221047f263f4Sek error = dmu_objset_rollback(os); 221147f263f4Sek resume_err = zfs_resume_fs(zfsvfs, osname, mode); 221247f263f4Sek error = error ? error : resume_err; 221347f263f4Sek } else { 221447f263f4Sek dmu_objset_close(os); 221547f263f4Sek } 22164ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 22174ccbb6e7Sahrens } else { 22184ccbb6e7Sahrens error = dmu_objset_rollback(os); 22194ccbb6e7Sahrens } 2220745cd3c5Smaybee /* Note, the dmu_objset_rollback() releases the objset for us. */ 22214ccbb6e7Sahrens 22224ccbb6e7Sahrens return (error); 2223fa9e4066Sahrens } 2224fa9e4066Sahrens 22253cb34c60Sahrens /* 22263cb34c60Sahrens * inputs: 22273cb34c60Sahrens * zc_name old name of dataset 22283cb34c60Sahrens * zc_value new name of dataset 22293cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 22303cb34c60Sahrens * 22313cb34c60Sahrens * outputs: none 22323cb34c60Sahrens */ 2233fa9e4066Sahrens static int 2234fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2235fa9e4066Sahrens { 22367f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 2237cdf5b4caSmmusante 2238e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2239f18faf3fSek if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2240f18faf3fSek strchr(zc->zc_value, '%')) 2241fa9e4066Sahrens return (EINVAL); 2242fa9e4066Sahrens 2243cdf5b4caSmmusante /* 2244cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 2245cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 2246cdf5b4caSmmusante * to unmount. 2247cdf5b4caSmmusante */ 2248cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2249fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 22501d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 22511d452cf5Sahrens if (err) 22521d452cf5Sahrens return (err); 2253fa9e4066Sahrens } 2254cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2255fa9e4066Sahrens } 2256fa9e4066Sahrens 2257745cd3c5Smaybee static void 2258745cd3c5Smaybee clear_props(char *dataset, nvlist_t *props) 2259745cd3c5Smaybee { 2260745cd3c5Smaybee zfs_cmd_t *zc; 2261745cd3c5Smaybee nvpair_t *prop; 2262745cd3c5Smaybee 2263745cd3c5Smaybee if (props == NULL) 2264745cd3c5Smaybee return; 2265745cd3c5Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 2266745cd3c5Smaybee (void) strcpy(zc->zc_name, dataset); 2267745cd3c5Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 2268745cd3c5Smaybee prop = nvlist_next_nvpair(props, prop)) { 2269745cd3c5Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 2270745cd3c5Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 2271745cd3c5Smaybee (void) zfs_ioc_inherit_prop(zc); 2272745cd3c5Smaybee } 2273745cd3c5Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 2274745cd3c5Smaybee } 2275745cd3c5Smaybee 22763cb34c60Sahrens /* 22773cb34c60Sahrens * inputs: 22783cb34c60Sahrens * zc_name name of containing filesystem 22793cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 22803cb34c60Sahrens * zc_value name of snapshot to create 22813cb34c60Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 22823cb34c60Sahrens * zc_cookie file descriptor to recv from 22833cb34c60Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 22843cb34c60Sahrens * zc_guid force flag 22853cb34c60Sahrens * 22863cb34c60Sahrens * outputs: 22873cb34c60Sahrens * zc_cookie number of bytes read 22883cb34c60Sahrens */ 2289fa9e4066Sahrens static int 22903cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2291fa9e4066Sahrens { 2292fa9e4066Sahrens file_t *fp; 2293f18faf3fSek objset_t *os; 22943cb34c60Sahrens dmu_recv_cookie_t drc; 2295f18faf3fSek zfsvfs_t *zfsvfs = NULL; 2296f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 2297f18faf3fSek int error, fd; 22983cb34c60Sahrens offset_t off; 22993cb34c60Sahrens nvlist_t *props = NULL; 2300745cd3c5Smaybee nvlist_t *origprops = NULL; 23013cb34c60Sahrens objset_t *origin = NULL; 23023cb34c60Sahrens char *tosnap; 23033cb34c60Sahrens char tofs[ZFS_MAXNAMELEN]; 2304fa9e4066Sahrens 23053ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2306f18faf3fSek strchr(zc->zc_value, '@') == NULL || 2307f18faf3fSek strchr(zc->zc_value, '%')) 23083ccfa83cSahrens return (EINVAL); 23093ccfa83cSahrens 23103cb34c60Sahrens (void) strcpy(tofs, zc->zc_value); 23113cb34c60Sahrens tosnap = strchr(tofs, '@'); 23123cb34c60Sahrens *tosnap = '\0'; 23133cb34c60Sahrens tosnap++; 23143cb34c60Sahrens 23153cb34c60Sahrens if (zc->zc_nvlist_src != NULL && 23163cb34c60Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 23173cb34c60Sahrens &props)) != 0) 23183cb34c60Sahrens return (error); 23193cb34c60Sahrens 2320fa9e4066Sahrens fd = zc->zc_cookie; 2321fa9e4066Sahrens fp = getf(fd); 23223cb34c60Sahrens if (fp == NULL) { 23233cb34c60Sahrens nvlist_free(props); 2324fa9e4066Sahrens return (EBADF); 23253cb34c60Sahrens } 2326f18faf3fSek 2327745cd3c5Smaybee if (dmu_objset_open(tofs, DMU_OST_ANY, 2328745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 2329745cd3c5Smaybee /* 2330745cd3c5Smaybee * Try to get the zfsvfs for the receiving objset. 2331745cd3c5Smaybee * There won't be one if we're operating on a zvol, 2332745cd3c5Smaybee * if the objset doesn't exist yet, or is not mounted. 2333745cd3c5Smaybee */ 23344ccbb6e7Sahrens mutex_enter(&os->os->os_user_ptr_lock); 2335745cd3c5Smaybee if (zfsvfs = dmu_objset_get_user(os)) { 233647f263f4Sek if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) { 2337745cd3c5Smaybee mutex_exit(&os->os->os_user_ptr_lock); 233847f263f4Sek dmu_objset_close(os); 2339745cd3c5Smaybee zfsvfs = NULL; 2340745cd3c5Smaybee error = EBUSY; 2341745cd3c5Smaybee goto out; 234247f263f4Sek } 2343745cd3c5Smaybee VFS_HOLD(zfsvfs->z_vfs); 234447f263f4Sek } 2345745cd3c5Smaybee mutex_exit(&os->os->os_user_ptr_lock); 2346745cd3c5Smaybee 2347745cd3c5Smaybee /* 2348745cd3c5Smaybee * If new properties are supplied, they are to completely 2349745cd3c5Smaybee * replace the existing ones, so stash away the existing ones. 2350745cd3c5Smaybee */ 2351745cd3c5Smaybee if (props) 2352745cd3c5Smaybee (void) dsl_prop_get_all(os, &origprops, TRUE); 2353745cd3c5Smaybee 2354f18faf3fSek dmu_objset_close(os); 2355f18faf3fSek } 2356f18faf3fSek 23573cb34c60Sahrens if (zc->zc_string[0]) { 23583cb34c60Sahrens error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 2359745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &origin); 2360745cd3c5Smaybee if (error) 2361745cd3c5Smaybee goto out; 23623cb34c60Sahrens } 23633cb34c60Sahrens 23643cb34c60Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 23653cb34c60Sahrens force, origin, zfsvfs != NULL, &drc); 23663cb34c60Sahrens if (origin) 23673cb34c60Sahrens dmu_objset_close(origin); 2368745cd3c5Smaybee if (error) 2369745cd3c5Smaybee goto out; 2370f18faf3fSek 2371f18faf3fSek /* 2372745cd3c5Smaybee * Reset properties. We do this before we receive the stream 2373745cd3c5Smaybee * so that the properties are applied to the new data. 2374f18faf3fSek */ 23753cb34c60Sahrens if (props) { 2376745cd3c5Smaybee clear_props(tofs, origprops); 2377745cd3c5Smaybee /* 2378745cd3c5Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 2379745cd3c5Smaybee */ 2380745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, props); 23813cb34c60Sahrens } 23823cb34c60Sahrens 23833cb34c60Sahrens off = fp->f_offset; 23843cb34c60Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 2385a2eea2e1Sahrens 2386745cd3c5Smaybee if (error == 0 && zfsvfs) { 2387745cd3c5Smaybee char osname[MAXNAMELEN]; 2388745cd3c5Smaybee int mode; 2389745cd3c5Smaybee 2390745cd3c5Smaybee /* online recv */ 2391745cd3c5Smaybee error = zfs_suspend_fs(zfsvfs, osname, &mode); 2392745cd3c5Smaybee if (error == 0) { 2393745cd3c5Smaybee int resume_err; 2394745cd3c5Smaybee 23953cb34c60Sahrens error = dmu_recv_end(&drc); 2396745cd3c5Smaybee resume_err = zfs_resume_fs(zfsvfs, osname, mode); 2397745cd3c5Smaybee error = error ? error : resume_err; 2398745cd3c5Smaybee } else { 2399745cd3c5Smaybee dmu_recv_abort_cleanup(&drc); 24003cb34c60Sahrens } 2401745cd3c5Smaybee } else if (error == 0) { 2402745cd3c5Smaybee error = dmu_recv_end(&drc); 240347f263f4Sek } 24043cb34c60Sahrens 24053cb34c60Sahrens zc->zc_cookie = off - fp->f_offset; 24063cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 24073cb34c60Sahrens fp->f_offset = off; 2408a2eea2e1Sahrens 2409745cd3c5Smaybee /* 2410745cd3c5Smaybee * On error, restore the original props. 2411745cd3c5Smaybee */ 2412745cd3c5Smaybee if (error && props) { 2413745cd3c5Smaybee clear_props(tofs, props); 2414745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 2415745cd3c5Smaybee } 2416745cd3c5Smaybee out: 2417745cd3c5Smaybee if (zfsvfs) { 2418745cd3c5Smaybee mutex_exit(&zfsvfs->z_online_recv_lock); 2419745cd3c5Smaybee VFS_RELE(zfsvfs->z_vfs); 2420745cd3c5Smaybee } 2421745cd3c5Smaybee nvlist_free(props); 2422745cd3c5Smaybee nvlist_free(origprops); 2423fa9e4066Sahrens releasef(fd); 2424fa9e4066Sahrens return (error); 2425fa9e4066Sahrens } 2426fa9e4066Sahrens 24273cb34c60Sahrens /* 24283cb34c60Sahrens * inputs: 24293cb34c60Sahrens * zc_name name of snapshot to send 24303cb34c60Sahrens * zc_value short name of incremental fromsnap (may be empty) 24313cb34c60Sahrens * zc_cookie file descriptor to send stream to 24323cb34c60Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 24333cb34c60Sahrens * 24343cb34c60Sahrens * outputs: none 24353cb34c60Sahrens */ 2436fa9e4066Sahrens static int 24373cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2438fa9e4066Sahrens { 2439fa9e4066Sahrens objset_t *fromsnap = NULL; 2440fa9e4066Sahrens objset_t *tosnap; 2441fa9e4066Sahrens file_t *fp; 2442fa9e4066Sahrens int error; 24433cb34c60Sahrens offset_t off; 2444fa9e4066Sahrens 2445fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 2446745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &tosnap); 2447fa9e4066Sahrens if (error) 2448fa9e4066Sahrens return (error); 2449fa9e4066Sahrens 2450e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 2451a2eea2e1Sahrens char buf[MAXPATHLEN]; 2452a2eea2e1Sahrens char *cp; 2453a2eea2e1Sahrens 2454a2eea2e1Sahrens (void) strncpy(buf, zc->zc_name, sizeof (buf)); 2455a2eea2e1Sahrens cp = strchr(buf, '@'); 2456a2eea2e1Sahrens if (cp) 2457a2eea2e1Sahrens *(cp+1) = 0; 2458a2eea2e1Sahrens (void) strncat(buf, zc->zc_value, sizeof (buf)); 2459a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 2460745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &fromsnap); 2461fa9e4066Sahrens if (error) { 2462fa9e4066Sahrens dmu_objset_close(tosnap); 2463fa9e4066Sahrens return (error); 2464fa9e4066Sahrens } 2465fa9e4066Sahrens } 2466fa9e4066Sahrens 2467fa9e4066Sahrens fp = getf(zc->zc_cookie); 2468fa9e4066Sahrens if (fp == NULL) { 2469fa9e4066Sahrens dmu_objset_close(tosnap); 2470fa9e4066Sahrens if (fromsnap) 2471fa9e4066Sahrens dmu_objset_close(fromsnap); 2472fa9e4066Sahrens return (EBADF); 2473fa9e4066Sahrens } 2474fa9e4066Sahrens 24753cb34c60Sahrens off = fp->f_offset; 24763cb34c60Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 2477fa9e4066Sahrens 24783cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 24793cb34c60Sahrens fp->f_offset = off; 2480fa9e4066Sahrens releasef(zc->zc_cookie); 2481fa9e4066Sahrens if (fromsnap) 2482fa9e4066Sahrens dmu_objset_close(fromsnap); 2483fa9e4066Sahrens dmu_objset_close(tosnap); 2484fa9e4066Sahrens return (error); 2485fa9e4066Sahrens } 2486fa9e4066Sahrens 2487ea8dc4b6Seschrock static int 2488ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 2489ea8dc4b6Seschrock { 2490ea8dc4b6Seschrock int id, error; 2491ea8dc4b6Seschrock 2492ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2493ea8dc4b6Seschrock &zc->zc_inject_record); 2494ea8dc4b6Seschrock 2495ea8dc4b6Seschrock if (error == 0) 2496ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 2497ea8dc4b6Seschrock 2498ea8dc4b6Seschrock return (error); 2499ea8dc4b6Seschrock } 2500ea8dc4b6Seschrock 2501ea8dc4b6Seschrock static int 2502ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 2503ea8dc4b6Seschrock { 2504ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 2505ea8dc4b6Seschrock } 2506ea8dc4b6Seschrock 2507ea8dc4b6Seschrock static int 2508ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2509ea8dc4b6Seschrock { 2510ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2511ea8dc4b6Seschrock int error; 2512ea8dc4b6Seschrock 2513ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2514ea8dc4b6Seschrock &zc->zc_inject_record); 2515ea8dc4b6Seschrock 2516ea8dc4b6Seschrock zc->zc_guid = id; 2517ea8dc4b6Seschrock 2518ea8dc4b6Seschrock return (error); 2519ea8dc4b6Seschrock } 2520ea8dc4b6Seschrock 2521ea8dc4b6Seschrock static int 2522ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2523ea8dc4b6Seschrock { 2524ea8dc4b6Seschrock spa_t *spa; 2525ea8dc4b6Seschrock int error; 2526e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2527ea8dc4b6Seschrock 2528ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2529ea8dc4b6Seschrock return (error); 2530ea8dc4b6Seschrock 2531e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2532ea8dc4b6Seschrock &count); 2533ea8dc4b6Seschrock if (error == 0) 2534e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2535ea8dc4b6Seschrock else 2536e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2537ea8dc4b6Seschrock 2538ea8dc4b6Seschrock spa_close(spa, FTAG); 2539ea8dc4b6Seschrock 2540ea8dc4b6Seschrock return (error); 2541ea8dc4b6Seschrock } 2542ea8dc4b6Seschrock 2543ea8dc4b6Seschrock static int 2544ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2545ea8dc4b6Seschrock { 2546ea8dc4b6Seschrock spa_t *spa; 2547ea8dc4b6Seschrock vdev_t *vd; 25483d7072f8Seschrock uint64_t txg; 2549bb8b5132Sek int error; 2550ea8dc4b6Seschrock 2551ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2552ea8dc4b6Seschrock return (error); 2553ea8dc4b6Seschrock 25540a4e9518Sgw /* 25550a4e9518Sgw * Try to resume any I/Os which may have been suspended 25560a4e9518Sgw * as a result of a complete pool failure. 25570a4e9518Sgw */ 25580a4e9518Sgw if (!list_is_empty(&spa->spa_zio_list)) { 25590a4e9518Sgw if (zio_vdev_resume_io(spa) != 0) { 25600a4e9518Sgw spa_close(spa, FTAG); 25610a4e9518Sgw return (EIO); 25620a4e9518Sgw } 25630a4e9518Sgw } 25640a4e9518Sgw 25653d7072f8Seschrock txg = spa_vdev_enter(spa); 2566ea8dc4b6Seschrock 2567e9dbad6fSeschrock if (zc->zc_guid == 0) { 2568ea8dc4b6Seschrock vd = NULL; 2569c5904d13Seschrock } else { 2570c5904d13Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 2571fa94a07fSbrendan if (vd == NULL) { 2572fa94a07fSbrendan (void) spa_vdev_exit(spa, NULL, txg, ENODEV); 2573fa94a07fSbrendan spa_close(spa, FTAG); 2574fa94a07fSbrendan return (ENODEV); 2575fa94a07fSbrendan } 2576ea8dc4b6Seschrock } 2577ea8dc4b6Seschrock 25780a4e9518Sgw vdev_clear(spa, vd, B_TRUE); 2579ea8dc4b6Seschrock 25803d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, 0); 2581ea8dc4b6Seschrock 2582ea8dc4b6Seschrock spa_close(spa, FTAG); 2583ea8dc4b6Seschrock 2584ea8dc4b6Seschrock return (0); 2585ea8dc4b6Seschrock } 2586ea8dc4b6Seschrock 25873cb34c60Sahrens /* 25883cb34c60Sahrens * inputs: 25893cb34c60Sahrens * zc_name name of filesystem 25903cb34c60Sahrens * zc_value name of origin snapshot 25913cb34c60Sahrens * 25923cb34c60Sahrens * outputs: none 25933cb34c60Sahrens */ 259499653d4eSeschrock static int 259599653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 259699653d4eSeschrock { 25970b69c2f0Sahrens char *cp; 25980b69c2f0Sahrens 25990b69c2f0Sahrens /* 26000b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 26010b69c2f0Sahrens * it's easier. 26020b69c2f0Sahrens */ 2603e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 26040b69c2f0Sahrens if (cp) 26050b69c2f0Sahrens *cp = '\0'; 2606e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 26070b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 260899653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 260999653d4eSeschrock } 261099653d4eSeschrock 2611ecd6cf80Smarks /* 2612ecd6cf80Smarks * We don't want to have a hard dependency 2613ecd6cf80Smarks * against some special symbols in sharefs 2614da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 2615ecd6cf80Smarks * the first file system is shared. 2616da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 2617ecd6cf80Smarks */ 2618da6c28aaSamw int (*znfsexport_fs)(void *arg); 2619ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2620da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 2621da6c28aaSamw 2622da6c28aaSamw int zfs_nfsshare_inited; 2623da6c28aaSamw int zfs_smbshare_inited; 2624ecd6cf80Smarks 2625ecd6cf80Smarks ddi_modhandle_t nfs_mod; 2626ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 2627da6c28aaSamw ddi_modhandle_t smbsrv_mod; 2628ecd6cf80Smarks kmutex_t zfs_share_lock; 2629ecd6cf80Smarks 2630da6c28aaSamw static int 2631da6c28aaSamw zfs_init_sharefs() 2632da6c28aaSamw { 2633da6c28aaSamw int error; 2634da6c28aaSamw 2635da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 2636da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 2637da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 2638da6c28aaSamw ddi_modopen("fs/sharefs", 2639da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2640da6c28aaSamw return (ENOSYS); 2641da6c28aaSamw } 2642da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 2643da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2644da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2645da6c28aaSamw return (ENOSYS); 2646da6c28aaSamw } 2647da6c28aaSamw return (0); 2648da6c28aaSamw } 2649da6c28aaSamw 2650ecd6cf80Smarks static int 2651ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 2652ecd6cf80Smarks { 2653ecd6cf80Smarks int error; 2654ecd6cf80Smarks int opcode; 2655ecd6cf80Smarks 2656da6c28aaSamw switch (zc->zc_share.z_sharetype) { 2657da6c28aaSamw case ZFS_SHARE_NFS: 2658da6c28aaSamw case ZFS_UNSHARE_NFS: 2659da6c28aaSamw if (zfs_nfsshare_inited == 0) { 2660da6c28aaSamw mutex_enter(&zfs_share_lock); 2661da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 2662da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2663da6c28aaSamw mutex_exit(&zfs_share_lock); 2664da6c28aaSamw return (ENOSYS); 2665da6c28aaSamw } 2666da6c28aaSamw if (znfsexport_fs == NULL && 2667da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 2668da6c28aaSamw ddi_modsym(nfs_mod, 2669da6c28aaSamw "nfs_export", &error)) == NULL)) { 2670da6c28aaSamw mutex_exit(&zfs_share_lock); 2671da6c28aaSamw return (ENOSYS); 2672da6c28aaSamw } 2673da6c28aaSamw error = zfs_init_sharefs(); 2674da6c28aaSamw if (error) { 2675da6c28aaSamw mutex_exit(&zfs_share_lock); 2676da6c28aaSamw return (ENOSYS); 2677da6c28aaSamw } 2678da6c28aaSamw zfs_nfsshare_inited = 1; 2679ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2680ecd6cf80Smarks } 2681da6c28aaSamw break; 2682da6c28aaSamw case ZFS_SHARE_SMB: 2683da6c28aaSamw case ZFS_UNSHARE_SMB: 2684da6c28aaSamw if (zfs_smbshare_inited == 0) { 2685da6c28aaSamw mutex_enter(&zfs_share_lock); 2686da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 2687da6c28aaSamw ddi_modopen("drv/smbsrv", 2688da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2689da6c28aaSamw mutex_exit(&zfs_share_lock); 2690da6c28aaSamw return (ENOSYS); 2691da6c28aaSamw } 2692da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 2693da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 2694faa1795aSjb "smb_server_share", &error)) == NULL)) { 2695da6c28aaSamw mutex_exit(&zfs_share_lock); 2696da6c28aaSamw return (ENOSYS); 2697da6c28aaSamw } 2698da6c28aaSamw error = zfs_init_sharefs(); 2699da6c28aaSamw if (error) { 2700da6c28aaSamw mutex_exit(&zfs_share_lock); 2701da6c28aaSamw return (ENOSYS); 2702da6c28aaSamw } 2703da6c28aaSamw zfs_smbshare_inited = 1; 2704ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2705ecd6cf80Smarks } 2706da6c28aaSamw break; 2707da6c28aaSamw default: 2708da6c28aaSamw return (EINVAL); 2709da6c28aaSamw } 2710ecd6cf80Smarks 2711da6c28aaSamw switch (zc->zc_share.z_sharetype) { 2712da6c28aaSamw case ZFS_SHARE_NFS: 2713da6c28aaSamw case ZFS_UNSHARE_NFS: 2714da6c28aaSamw if (error = 2715da6c28aaSamw znfsexport_fs((void *) 2716da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 2717da6c28aaSamw return (error); 2718da6c28aaSamw break; 2719da6c28aaSamw case ZFS_SHARE_SMB: 2720da6c28aaSamw case ZFS_UNSHARE_SMB: 2721da6c28aaSamw if (error = zsmbexport_fs((void *) 2722da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 2723da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 2724da6c28aaSamw B_TRUE : B_FALSE)) { 2725da6c28aaSamw return (error); 2726ecd6cf80Smarks } 2727da6c28aaSamw break; 2728ecd6cf80Smarks } 2729ecd6cf80Smarks 2730da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 2731da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 2732ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 2733ecd6cf80Smarks 2734da6c28aaSamw /* 2735da6c28aaSamw * Add or remove share from sharetab 2736da6c28aaSamw */ 2737ecd6cf80Smarks error = zshare_fs(opcode, 2738ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 2739ecd6cf80Smarks zc->zc_share.z_sharemax); 2740ecd6cf80Smarks 2741ecd6cf80Smarks return (error); 2742ecd6cf80Smarks 2743ecd6cf80Smarks } 2744ecd6cf80Smarks 2745ecd6cf80Smarks /* 27462a6b87f0Sek * pool create, destroy, and export don't log the history as part of 27472a6b87f0Sek * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 27482a6b87f0Sek * do the logging of those commands. 2749ecd6cf80Smarks */ 2750fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 2751228975ccSek { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2752e7437265Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2753e7437265Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2754e7437265Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2755e7437265Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 2756e7437265Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2757e7437265Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2758e7437265Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2759e7437265Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2760e7437265Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2761e7437265Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2762e7437265Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2763e7437265Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2764e7437265Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2765e7437265Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2766e7437265Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2767e7437265Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2768e7437265Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2769de8267e0Stimh { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2770ecd6cf80Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 2771e7437265Sahrens DATASET_NAME, B_FALSE }, 2772ecd6cf80Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 2773e7437265Sahrens DATASET_NAME, B_FALSE }, 2774e7437265Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 2775e7437265Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2776e7437265Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2777e7437265Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 2778e7437265Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2779e7437265Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 2780e7437265Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 27813cb34c60Sahrens { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 27823cb34c60Sahrens { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 2783e7437265Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2784e7437265Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2785e7437265Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2786e7437265Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 2787e7437265Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2788e7437265Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 2789e7437265Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2790e7437265Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 2791e7437265Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2792e7437265Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2793e7437265Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2794e7437265Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2795e7437265Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 2796e7437265Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2797ecd6cf80Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 2798e7437265Sahrens DATASET_NAME, B_FALSE }, 2799e45ce728Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 2800e45ce728Sahrens { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 2801fa9e4066Sahrens }; 2802fa9e4066Sahrens 2803fa9e4066Sahrens static int 2804fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2805fa9e4066Sahrens { 2806fa9e4066Sahrens zfs_cmd_t *zc; 2807fa9e4066Sahrens uint_t vec; 28081d452cf5Sahrens int error, rc; 2809fa9e4066Sahrens 2810fa9e4066Sahrens if (getminor(dev) != 0) 2811fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2812fa9e4066Sahrens 2813fa9e4066Sahrens vec = cmd - ZFS_IOC; 281491ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 2815fa9e4066Sahrens 2816fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2817fa9e4066Sahrens return (EINVAL); 2818fa9e4066Sahrens 2819fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2820fa9e4066Sahrens 2821fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2822fa9e4066Sahrens 282391ebeef5Sahrens if (error == 0) 2824ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2825fa9e4066Sahrens 2826fa9e4066Sahrens /* 2827fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2828fa9e4066Sahrens * the lower layers. 2829fa9e4066Sahrens */ 2830fa9e4066Sahrens if (error == 0) { 2831fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2832fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 2833e7437265Sahrens case POOL_NAME: 2834fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2835fa9e4066Sahrens error = EINVAL; 2836fa9e4066Sahrens break; 2837fa9e4066Sahrens 2838e7437265Sahrens case DATASET_NAME: 2839fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2840fa9e4066Sahrens error = EINVAL; 2841fa9e4066Sahrens break; 28425ad82045Snd 2843e7437265Sahrens case NO_NAME: 28445ad82045Snd break; 2845fa9e4066Sahrens } 2846fa9e4066Sahrens } 2847fa9e4066Sahrens 2848fa9e4066Sahrens if (error == 0) 2849fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2850fa9e4066Sahrens 28511d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 2852ecd6cf80Smarks if (error == 0) { 28531d452cf5Sahrens error = rc; 2854ecd6cf80Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 2855ecd6cf80Smarks zfs_log_history(zc); 2856ecd6cf80Smarks } 2857fa9e4066Sahrens 2858fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 2859fa9e4066Sahrens return (error); 2860fa9e4066Sahrens } 2861fa9e4066Sahrens 2862fa9e4066Sahrens static int 2863fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2864fa9e4066Sahrens { 2865fa9e4066Sahrens if (cmd != DDI_ATTACH) 2866fa9e4066Sahrens return (DDI_FAILURE); 2867fa9e4066Sahrens 2868fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 2869fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 2870fa9e4066Sahrens return (DDI_FAILURE); 2871fa9e4066Sahrens 2872fa9e4066Sahrens zfs_dip = dip; 2873fa9e4066Sahrens 2874fa9e4066Sahrens ddi_report_dev(dip); 2875fa9e4066Sahrens 2876fa9e4066Sahrens return (DDI_SUCCESS); 2877fa9e4066Sahrens } 2878fa9e4066Sahrens 2879fa9e4066Sahrens static int 2880fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2881fa9e4066Sahrens { 2882fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 2883fa9e4066Sahrens return (DDI_FAILURE); 2884fa9e4066Sahrens 2885fa9e4066Sahrens if (cmd != DDI_DETACH) 2886fa9e4066Sahrens return (DDI_FAILURE); 2887fa9e4066Sahrens 2888fa9e4066Sahrens zfs_dip = NULL; 2889fa9e4066Sahrens 2890fa9e4066Sahrens ddi_prop_remove_all(dip); 2891fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 2892fa9e4066Sahrens 2893fa9e4066Sahrens return (DDI_SUCCESS); 2894fa9e4066Sahrens } 2895fa9e4066Sahrens 2896fa9e4066Sahrens /*ARGSUSED*/ 2897fa9e4066Sahrens static int 2898fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2899fa9e4066Sahrens { 2900fa9e4066Sahrens switch (infocmd) { 2901fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 2902fa9e4066Sahrens *result = zfs_dip; 2903fa9e4066Sahrens return (DDI_SUCCESS); 2904fa9e4066Sahrens 2905fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 2906a0965f35Sbonwick *result = (void *)0; 2907fa9e4066Sahrens return (DDI_SUCCESS); 2908fa9e4066Sahrens } 2909fa9e4066Sahrens 2910fa9e4066Sahrens return (DDI_FAILURE); 2911fa9e4066Sahrens } 2912fa9e4066Sahrens 2913fa9e4066Sahrens /* 2914fa9e4066Sahrens * OK, so this is a little weird. 2915fa9e4066Sahrens * 2916fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 2917fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 2918fa9e4066Sahrens * 2919fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 2920fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 2921fa9e4066Sahrens */ 2922fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 2923fa9e4066Sahrens zvol_open, /* open */ 2924fa9e4066Sahrens zvol_close, /* close */ 2925fa9e4066Sahrens zvol_strategy, /* strategy */ 2926fa9e4066Sahrens nodev, /* print */ 2927e7cbe64fSgw zvol_dump, /* dump */ 2928fa9e4066Sahrens zvol_read, /* read */ 2929fa9e4066Sahrens zvol_write, /* write */ 2930fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 2931fa9e4066Sahrens nodev, /* devmap */ 2932fa9e4066Sahrens nodev, /* mmap */ 2933fa9e4066Sahrens nodev, /* segmap */ 2934fa9e4066Sahrens nochpoll, /* poll */ 2935fa9e4066Sahrens ddi_prop_op, /* prop_op */ 2936fa9e4066Sahrens NULL, /* streamtab */ 2937fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 2938fa9e4066Sahrens CB_REV, /* version */ 2939feb08c6bSbillm nodev, /* async read */ 2940feb08c6bSbillm nodev, /* async write */ 2941fa9e4066Sahrens }; 2942fa9e4066Sahrens 2943fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 2944fa9e4066Sahrens DEVO_REV, /* version */ 2945fa9e4066Sahrens 0, /* refcnt */ 2946fa9e4066Sahrens zfs_info, /* info */ 2947fa9e4066Sahrens nulldev, /* identify */ 2948fa9e4066Sahrens nulldev, /* probe */ 2949fa9e4066Sahrens zfs_attach, /* attach */ 2950fa9e4066Sahrens zfs_detach, /* detach */ 2951fa9e4066Sahrens nodev, /* reset */ 2952fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 2953fa9e4066Sahrens NULL /* no bus operations */ 2954fa9e4066Sahrens }; 2955fa9e4066Sahrens 2956fa9e4066Sahrens static struct modldrv zfs_modldrv = { 2957e7437265Sahrens &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, 2958e9dbad6fSeschrock &zfs_dev_ops 2959fa9e4066Sahrens }; 2960fa9e4066Sahrens 2961fa9e4066Sahrens static struct modlinkage modlinkage = { 2962fa9e4066Sahrens MODREV_1, 2963fa9e4066Sahrens (void *)&zfs_modlfs, 2964fa9e4066Sahrens (void *)&zfs_modldrv, 2965fa9e4066Sahrens NULL 2966fa9e4066Sahrens }; 2967fa9e4066Sahrens 2968ec533521Sfr 2969ec533521Sfr uint_t zfs_fsyncer_key; 2970f18faf3fSek extern uint_t rrw_tsd_key; 2971ec533521Sfr 2972fa9e4066Sahrens int 2973fa9e4066Sahrens _init(void) 2974fa9e4066Sahrens { 2975fa9e4066Sahrens int error; 2976fa9e4066Sahrens 2977a0965f35Sbonwick spa_init(FREAD | FWRITE); 2978a0965f35Sbonwick zfs_init(); 2979a0965f35Sbonwick zvol_init(); 2980a0965f35Sbonwick 2981a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 2982a0965f35Sbonwick zvol_fini(); 2983a0965f35Sbonwick zfs_fini(); 2984a0965f35Sbonwick spa_fini(); 2985fa9e4066Sahrens return (error); 2986a0965f35Sbonwick } 2987fa9e4066Sahrens 2988ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 2989f18faf3fSek tsd_create(&rrw_tsd_key, NULL); 2990ec533521Sfr 2991fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 2992fa9e4066Sahrens ASSERT(error == 0); 2993ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 2994fa9e4066Sahrens 2995fa9e4066Sahrens return (0); 2996fa9e4066Sahrens } 2997fa9e4066Sahrens 2998fa9e4066Sahrens int 2999fa9e4066Sahrens _fini(void) 3000fa9e4066Sahrens { 3001fa9e4066Sahrens int error; 3002fa9e4066Sahrens 3003ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3004fa9e4066Sahrens return (EBUSY); 3005fa9e4066Sahrens 3006fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3007fa9e4066Sahrens return (error); 3008fa9e4066Sahrens 3009fa9e4066Sahrens zvol_fini(); 3010fa9e4066Sahrens zfs_fini(); 3011fa9e4066Sahrens spa_fini(); 3012da6c28aaSamw if (zfs_nfsshare_inited) 3013ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 3014da6c28aaSamw if (zfs_smbshare_inited) 3015da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 3016da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 3017ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 3018fa9e4066Sahrens 3019ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 3020fa9e4066Sahrens ldi_ident_release(zfs_li); 3021fa9e4066Sahrens zfs_li = NULL; 3022ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 3023fa9e4066Sahrens 3024fa9e4066Sahrens return (error); 3025fa9e4066Sahrens } 3026fa9e4066Sahrens 3027fa9e4066Sahrens int 3028fa9e4066Sahrens _info(struct modinfo *modinfop) 3029fa9e4066Sahrens { 3030fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 3031fa9e4066Sahrens } 3032