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 /* 2255434c77Sek * Copyright 2007 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> 41fa9e4066Sahrens #include <sys/zap.h> 42fa9e4066Sahrens #include <sys/spa.h> 43b1b8ab34Slling #include <sys/spa_impl.h> 44fa9e4066Sahrens #include <sys/vdev.h> 45b1b8ab34Slling #include <sys/vdev_impl.h> 46fa9e4066Sahrens #include <sys/dmu.h> 47fa9e4066Sahrens #include <sys/dsl_dir.h> 48fa9e4066Sahrens #include <sys/dsl_dataset.h> 49fa9e4066Sahrens #include <sys/dsl_prop.h> 50*ecd6cf80Smarks #include <sys/dsl_deleg.h> 51*ecd6cf80Smarks #include <sys/dmu_objset.h> 52fa9e4066Sahrens #include <sys/ddi.h> 53fa9e4066Sahrens #include <sys/sunddi.h> 54fa9e4066Sahrens #include <sys/sunldi.h> 55fa9e4066Sahrens #include <sys/policy.h> 56fa9e4066Sahrens #include <sys/zone.h> 57fa9e4066Sahrens #include <sys/nvpair.h> 58fa9e4066Sahrens #include <sys/pathname.h> 59fa9e4066Sahrens #include <sys/mount.h> 60fa9e4066Sahrens #include <sys/sdt.h> 61fa9e4066Sahrens #include <sys/fs/zfs.h> 62fa9e4066Sahrens #include <sys/zfs_ctldir.h> 63a2eea2e1Sahrens #include <sys/zvol.h> 64*ecd6cf80Smarks #include <sharefs/share.h> 65fa9e4066Sahrens 66fa9e4066Sahrens #include "zfs_namecheck.h" 67e9dbad6fSeschrock #include "zfs_prop.h" 68*ecd6cf80Smarks #include "zfs_deleg.h" 69fa9e4066Sahrens 70fa9e4066Sahrens extern struct modlfs zfs_modlfs; 71fa9e4066Sahrens 72fa9e4066Sahrens extern void zfs_init(void); 73fa9e4066Sahrens extern void zfs_fini(void); 74fa9e4066Sahrens 75fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 76fa9e4066Sahrens dev_info_t *zfs_dip; 77fa9e4066Sahrens 78fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 79*ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 80fa9e4066Sahrens 81fa9e4066Sahrens typedef struct zfs_ioc_vec { 82fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 83fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 84fa9e4066Sahrens enum { 85fa9e4066Sahrens no_name, 86fa9e4066Sahrens pool_name, 87fa9e4066Sahrens dataset_name 88*ecd6cf80Smarks } zvec_namecheck; 89*ecd6cf80Smarks boolean_t zvec_his_log; 90fa9e4066Sahrens } zfs_ioc_vec_t; 91fa9e4066Sahrens 92fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 93fa9e4066Sahrens void 94fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 95fa9e4066Sahrens { 96fa9e4066Sahrens const char *newfile; 97fa9e4066Sahrens char buf[256]; 98fa9e4066Sahrens va_list adx; 99fa9e4066Sahrens 100fa9e4066Sahrens /* 101fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 102fa9e4066Sahrens */ 103fa9e4066Sahrens newfile = strrchr(file, '/'); 104fa9e4066Sahrens if (newfile != NULL) { 105fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 106fa9e4066Sahrens } else { 107fa9e4066Sahrens newfile = file; 108fa9e4066Sahrens } 109fa9e4066Sahrens 110fa9e4066Sahrens va_start(adx, fmt); 111fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 112fa9e4066Sahrens va_end(adx); 113fa9e4066Sahrens 114fa9e4066Sahrens /* 115fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 116fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 117fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 118fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 119fa9e4066Sahrens * arg0 = file name 120fa9e4066Sahrens * arg1 = function name 121fa9e4066Sahrens * arg2 = line number 122fa9e4066Sahrens * arg3 = message 123fa9e4066Sahrens */ 124fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 125fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 126fa9e4066Sahrens } 127fa9e4066Sahrens 128*ecd6cf80Smarks static void 129*ecd6cf80Smarks zfs_log_history(zfs_cmd_t *zc) 130*ecd6cf80Smarks { 131*ecd6cf80Smarks spa_t *spa; 132*ecd6cf80Smarks char poolname[MAXNAMELEN]; 133*ecd6cf80Smarks char *buf, *cp; 134*ecd6cf80Smarks 135*ecd6cf80Smarks if (zc->zc_history == NULL) 136*ecd6cf80Smarks return; 137*ecd6cf80Smarks 138*ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 139*ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 140*ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 141*ecd6cf80Smarks kmem_free(buf, HIS_MAX_RECORD_LEN); 142*ecd6cf80Smarks return; 143*ecd6cf80Smarks } 144*ecd6cf80Smarks 145*ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 146*ecd6cf80Smarks 147*ecd6cf80Smarks (void) strlcpy(poolname, zc->zc_name, sizeof (poolname)); 148*ecd6cf80Smarks cp = strpbrk(poolname, "/@"); 149*ecd6cf80Smarks if (cp != NULL) 150*ecd6cf80Smarks *cp = '\0'; 151*ecd6cf80Smarks 152*ecd6cf80Smarks if (spa_open(poolname, &spa, FTAG) != 0) { 153*ecd6cf80Smarks kmem_free(buf, HIS_MAX_RECORD_LEN); 154*ecd6cf80Smarks return; 155*ecd6cf80Smarks } 156*ecd6cf80Smarks 157*ecd6cf80Smarks if (spa_version(spa) >= ZFS_VERSION_ZPOOL_HISTORY) 158*ecd6cf80Smarks (void) spa_history_log(spa, buf, zc->zc_history_offset); 159*ecd6cf80Smarks 160*ecd6cf80Smarks spa_close(spa, FTAG); 161*ecd6cf80Smarks kmem_free(buf, HIS_MAX_RECORD_LEN); 162*ecd6cf80Smarks } 163*ecd6cf80Smarks 164fa9e4066Sahrens /* 165fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 166fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 167fa9e4066Sahrens */ 168fa9e4066Sahrens /* ARGSUSED */ 169fa9e4066Sahrens static int 170*ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 171fa9e4066Sahrens { 172fa9e4066Sahrens return (0); 173fa9e4066Sahrens } 174fa9e4066Sahrens 175fa9e4066Sahrens /* 176fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 177fa9e4066Sahrens * no privileges, but must be visible in the local zone. 178fa9e4066Sahrens */ 179fa9e4066Sahrens /* ARGSUSED */ 180fa9e4066Sahrens static int 181*ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 182fa9e4066Sahrens { 183fa9e4066Sahrens if (INGLOBALZONE(curproc) || 184*ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 185fa9e4066Sahrens return (0); 186fa9e4066Sahrens 187fa9e4066Sahrens return (ENOENT); 188fa9e4066Sahrens } 189fa9e4066Sahrens 190fa9e4066Sahrens static int 191fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 192fa9e4066Sahrens { 193fa9e4066Sahrens uint64_t zoned; 194fa9e4066Sahrens int writable = 1; 195fa9e4066Sahrens 196fa9e4066Sahrens /* 197fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 198fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 199fa9e4066Sahrens */ 200fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 201fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 202fa9e4066Sahrens return (ENOENT); 203fa9e4066Sahrens 204fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 205fa9e4066Sahrens return (ENOENT); 206fa9e4066Sahrens 207fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 208fa9e4066Sahrens /* 209fa9e4066Sahrens * If the fs is zoned, only root can access it from the 210fa9e4066Sahrens * global zone. 211fa9e4066Sahrens */ 212fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 213fa9e4066Sahrens return (EPERM); 214fa9e4066Sahrens } else { 215fa9e4066Sahrens /* 216fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 217fa9e4066Sahrens */ 218fa9e4066Sahrens if (!zoned) 219fa9e4066Sahrens return (EPERM); 220fa9e4066Sahrens 221fa9e4066Sahrens /* must be writable by this zone */ 222fa9e4066Sahrens if (!writable) 223fa9e4066Sahrens return (EPERM); 224fa9e4066Sahrens } 225fa9e4066Sahrens return (0); 226fa9e4066Sahrens } 227fa9e4066Sahrens 228fa9e4066Sahrens int 229*ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 230fa9e4066Sahrens { 231fa9e4066Sahrens int error; 232fa9e4066Sahrens 233*ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 234*ecd6cf80Smarks if (error == 0) { 235*ecd6cf80Smarks error = secpolicy_zfs(cr); 236*ecd6cf80Smarks if (error) { 237*ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 238*ecd6cf80Smarks } 239*ecd6cf80Smarks } 240*ecd6cf80Smarks return (error); 241*ecd6cf80Smarks } 242*ecd6cf80Smarks 243*ecd6cf80Smarks static int 244*ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 245*ecd6cf80Smarks { 246*ecd6cf80Smarks int error = 0; 247*ecd6cf80Smarks 248*ecd6cf80Smarks /* 249*ecd6cf80Smarks * Check permissions for special properties. 250*ecd6cf80Smarks */ 251*ecd6cf80Smarks switch (prop) { 252*ecd6cf80Smarks case ZFS_PROP_ZONED: 253*ecd6cf80Smarks /* 254*ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 255*ecd6cf80Smarks */ 256*ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 257*ecd6cf80Smarks return (EPERM); 258*ecd6cf80Smarks break; 259*ecd6cf80Smarks 260*ecd6cf80Smarks case ZFS_PROP_QUOTA: 261*ecd6cf80Smarks if (error = 262*ecd6cf80Smarks zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_QUOTA, cr)) 263*ecd6cf80Smarks return (error); 264*ecd6cf80Smarks 265*ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 266*ecd6cf80Smarks uint64_t zoned; 267*ecd6cf80Smarks char setpoint[MAXNAMELEN]; 268*ecd6cf80Smarks int dslen; 269*ecd6cf80Smarks /* 270*ecd6cf80Smarks * Unprivileged users are allowed to modify the 271*ecd6cf80Smarks * quota on things *under* (ie. contained by) 272*ecd6cf80Smarks * the thing they own. 273*ecd6cf80Smarks */ 274*ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 275*ecd6cf80Smarks setpoint)) 276*ecd6cf80Smarks return (EPERM); 277*ecd6cf80Smarks if (!zoned) /* this shouldn't happen */ 278*ecd6cf80Smarks return (EPERM); 279*ecd6cf80Smarks dslen = strlen(name); 280*ecd6cf80Smarks if (dslen <= strlen(setpoint)) 281*ecd6cf80Smarks return (EPERM); 282*ecd6cf80Smarks } 283*ecd6cf80Smarks default: 284*ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 285*ecd6cf80Smarks zfs_prop_perm(prop), cr); 286*ecd6cf80Smarks } 287*ecd6cf80Smarks 288*ecd6cf80Smarks return (error); 289*ecd6cf80Smarks } 290*ecd6cf80Smarks 291*ecd6cf80Smarks int 292*ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 293*ecd6cf80Smarks { 294*ecd6cf80Smarks int error; 295*ecd6cf80Smarks 296*ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 297*ecd6cf80Smarks if (error) 298fa9e4066Sahrens return (error); 299fa9e4066Sahrens 300*ecd6cf80Smarks /* 301*ecd6cf80Smarks * permission to set permissions will be evaluated later in 302*ecd6cf80Smarks * dsl_deleg_can_allow() 303*ecd6cf80Smarks */ 304*ecd6cf80Smarks return (0); 305*ecd6cf80Smarks } 306*ecd6cf80Smarks 307*ecd6cf80Smarks int 308*ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 309*ecd6cf80Smarks { 310*ecd6cf80Smarks int error; 311*ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 312*ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 313*ecd6cf80Smarks if (error == 0) 314*ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 315*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 316*ecd6cf80Smarks return (error); 317*ecd6cf80Smarks } 318*ecd6cf80Smarks 319*ecd6cf80Smarks int 320*ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 321*ecd6cf80Smarks { 322*ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 323*ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 324*ecd6cf80Smarks } 325*ecd6cf80Smarks 326*ecd6cf80Smarks int 327*ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 328*ecd6cf80Smarks { 329*ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 330*ecd6cf80Smarks return (EPERM); 331*ecd6cf80Smarks 332*ecd6cf80Smarks if (secpolicy_nfs(CRED()) == 0) { 333*ecd6cf80Smarks return (0); 334*ecd6cf80Smarks } else { 335*ecd6cf80Smarks vnode_t *vp; 336*ecd6cf80Smarks int error; 337*ecd6cf80Smarks 338*ecd6cf80Smarks if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 339*ecd6cf80Smarks NO_FOLLOW, NULL, &vp)) != 0) 340*ecd6cf80Smarks return (error); 341*ecd6cf80Smarks 342*ecd6cf80Smarks /* Now make sure mntpnt and dataset are ZFS */ 343*ecd6cf80Smarks 344*ecd6cf80Smarks if (vp->v_vfsp->vfs_fstype != zfsfstype || 345*ecd6cf80Smarks (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 346*ecd6cf80Smarks zc->zc_name) != 0)) { 347*ecd6cf80Smarks VN_RELE(vp); 348*ecd6cf80Smarks return (EPERM); 349*ecd6cf80Smarks } 350*ecd6cf80Smarks 351*ecd6cf80Smarks VN_RELE(vp); 352*ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 353*ecd6cf80Smarks ZFS_DELEG_PERM_SHARE, cr)); 354*ecd6cf80Smarks } 355fa9e4066Sahrens } 356fa9e4066Sahrens 357fa9e4066Sahrens static int 358*ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 359fa9e4066Sahrens { 360fa9e4066Sahrens char *cp; 361fa9e4066Sahrens 362fa9e4066Sahrens /* 363fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 364fa9e4066Sahrens */ 365*ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 366*ecd6cf80Smarks cp = strrchr(parent, '@'); 367fa9e4066Sahrens if (cp != NULL) { 368fa9e4066Sahrens cp[0] = '\0'; 369fa9e4066Sahrens } else { 370*ecd6cf80Smarks cp = strrchr(parent, '/'); 371fa9e4066Sahrens if (cp == NULL) 372fa9e4066Sahrens return (ENOENT); 373fa9e4066Sahrens cp[0] = '\0'; 374*ecd6cf80Smarks } 375*ecd6cf80Smarks 376*ecd6cf80Smarks return (0); 377*ecd6cf80Smarks } 378*ecd6cf80Smarks 379*ecd6cf80Smarks int 380*ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 381*ecd6cf80Smarks { 382*ecd6cf80Smarks int error; 383*ecd6cf80Smarks 384*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 385*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 386*ecd6cf80Smarks return (error); 387*ecd6cf80Smarks 388*ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 389*ecd6cf80Smarks } 390*ecd6cf80Smarks 391*ecd6cf80Smarks static int 392*ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 393*ecd6cf80Smarks { 394*ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 395*ecd6cf80Smarks } 396*ecd6cf80Smarks 397*ecd6cf80Smarks /* 398*ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 399*ecd6cf80Smarks */ 400*ecd6cf80Smarks /* ARGSUSED */ 401*ecd6cf80Smarks static int 402*ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 403*ecd6cf80Smarks { 404*ecd6cf80Smarks return (secpolicy_zfs(cr)); 405*ecd6cf80Smarks } 406*ecd6cf80Smarks 407*ecd6cf80Smarks int 408*ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 409*ecd6cf80Smarks { 410*ecd6cf80Smarks char parentname[MAXNAMELEN]; 411*ecd6cf80Smarks int error; 412*ecd6cf80Smarks 413*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 414*ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 415*ecd6cf80Smarks return (error); 416*ecd6cf80Smarks 417*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 418*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 419*ecd6cf80Smarks return (error); 420*ecd6cf80Smarks 421*ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 422*ecd6cf80Smarks sizeof (parentname))) != 0) 423*ecd6cf80Smarks return (error); 424*ecd6cf80Smarks 425*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 426*ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 427*ecd6cf80Smarks return (error); 428*ecd6cf80Smarks 429*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 430*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 431*ecd6cf80Smarks return (error); 432*ecd6cf80Smarks 433*ecd6cf80Smarks return (error); 434*ecd6cf80Smarks } 435*ecd6cf80Smarks 436*ecd6cf80Smarks static int 437*ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 438*ecd6cf80Smarks { 439*ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 440*ecd6cf80Smarks } 441*ecd6cf80Smarks 442*ecd6cf80Smarks static int 443*ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 444*ecd6cf80Smarks { 445*ecd6cf80Smarks char parentname[MAXNAMELEN]; 446*ecd6cf80Smarks objset_t *clone; 447*ecd6cf80Smarks int error; 448*ecd6cf80Smarks 449*ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 450*ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 451*ecd6cf80Smarks if (error) 452*ecd6cf80Smarks return (error); 453*ecd6cf80Smarks 454*ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 455*ecd6cf80Smarks DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 456*ecd6cf80Smarks 457*ecd6cf80Smarks if (error == 0) { 458*ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 459*ecd6cf80Smarks dsl_dir_t *dd; 460*ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 461*ecd6cf80Smarks 462*ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 463*ecd6cf80Smarks error = dsl_dataset_open_obj(dd->dd_pool, 464*ecd6cf80Smarks dd->dd_phys->dd_clone_parent_obj, NULL, 465*ecd6cf80Smarks DS_MODE_NONE, FTAG, &pclone); 466*ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 467*ecd6cf80Smarks if (error) { 468*ecd6cf80Smarks dmu_objset_close(clone); 469*ecd6cf80Smarks return (error); 470*ecd6cf80Smarks } 471*ecd6cf80Smarks 472*ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 473*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 474*ecd6cf80Smarks 475*ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 476*ecd6cf80Smarks dmu_objset_close(clone); 477*ecd6cf80Smarks dsl_dataset_close(pclone, DS_MODE_NONE, FTAG); 478*ecd6cf80Smarks if (error == 0) 479*ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 480*ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 481*ecd6cf80Smarks } 482*ecd6cf80Smarks return (error); 483*ecd6cf80Smarks } 484*ecd6cf80Smarks 485*ecd6cf80Smarks static int 486*ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 487*ecd6cf80Smarks { 488*ecd6cf80Smarks int error; 489*ecd6cf80Smarks 490*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 491*ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 492*ecd6cf80Smarks return (error); 493*ecd6cf80Smarks 494*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 495*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 496*ecd6cf80Smarks return (error); 497*ecd6cf80Smarks 498*ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 499*ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 500*ecd6cf80Smarks } 501*ecd6cf80Smarks 502*ecd6cf80Smarks int 503*ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 504*ecd6cf80Smarks { 505*ecd6cf80Smarks int error; 506*ecd6cf80Smarks 507*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 508*ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 509*ecd6cf80Smarks return (error); 510*ecd6cf80Smarks 511*ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 512*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 513*ecd6cf80Smarks 514*ecd6cf80Smarks return (error); 515*ecd6cf80Smarks } 516*ecd6cf80Smarks 517*ecd6cf80Smarks static int 518*ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 519*ecd6cf80Smarks { 520*ecd6cf80Smarks 521*ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 522*ecd6cf80Smarks } 523*ecd6cf80Smarks 524*ecd6cf80Smarks 525*ecd6cf80Smarks 526*ecd6cf80Smarks static int 527*ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 528*ecd6cf80Smarks { 529*ecd6cf80Smarks char parentname[MAXNAMELEN]; 530*ecd6cf80Smarks int error; 531*ecd6cf80Smarks 532*ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 533*ecd6cf80Smarks sizeof (parentname))) != 0) 534*ecd6cf80Smarks return (error); 535fa9e4066Sahrens 536*ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 537*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 538*ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 539*ecd6cf80Smarks return (error); 540fa9e4066Sahrens } 541fa9e4066Sahrens 542*ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 543*ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 544*ecd6cf80Smarks return (error); 545*ecd6cf80Smarks 546*ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 547*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 548*ecd6cf80Smarks 549*ecd6cf80Smarks return (error); 550*ecd6cf80Smarks } 551*ecd6cf80Smarks 552*ecd6cf80Smarks static int 553*ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 554*ecd6cf80Smarks { 555*ecd6cf80Smarks int error; 556*ecd6cf80Smarks 557*ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 558*ecd6cf80Smarks if (error) { 559*ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 560*ecd6cf80Smarks } 561*ecd6cf80Smarks return (error); 562fa9e4066Sahrens } 563fa9e4066Sahrens 564fa9e4066Sahrens /* 565fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 566fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 567fa9e4066Sahrens */ 568fa9e4066Sahrens /* ARGSUSED */ 569fa9e4066Sahrens static int 570*ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 571fa9e4066Sahrens { 572fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 573fa9e4066Sahrens return (EPERM); 574fa9e4066Sahrens 575fa9e4066Sahrens return (0); 576fa9e4066Sahrens } 577fa9e4066Sahrens 578*ecd6cf80Smarks /* 579*ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 580*ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 581*ecd6cf80Smarks * the minor nodes. 582*ecd6cf80Smarks */ 583*ecd6cf80Smarks static int 584*ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 585*ecd6cf80Smarks { 586*ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 587*ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 588*ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 589*ecd6cf80Smarks } 590*ecd6cf80Smarks 591*ecd6cf80Smarks return (0); 592*ecd6cf80Smarks } 593*ecd6cf80Smarks 594ea8dc4b6Seschrock /* 595ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 596ea8dc4b6Seschrock */ 597ea8dc4b6Seschrock /* ARGSUSED */ 598ea8dc4b6Seschrock static int 599*ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 600ea8dc4b6Seschrock { 601ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 602ea8dc4b6Seschrock } 603ea8dc4b6Seschrock 604fa9e4066Sahrens /* 605fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 606fa9e4066Sahrens */ 607fa9e4066Sahrens static int 608e9dbad6fSeschrock get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp) 609fa9e4066Sahrens { 610fa9e4066Sahrens char *packed; 611fa9e4066Sahrens size_t size; 612fa9e4066Sahrens int error; 613fa9e4066Sahrens nvlist_t *config = NULL; 614fa9e4066Sahrens 615fa9e4066Sahrens /* 616e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 617fa9e4066Sahrens */ 618e9dbad6fSeschrock if ((size = zc->zc_nvlist_src_size) == 0) 619fa9e4066Sahrens return (EINVAL); 620fa9e4066Sahrens 621fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 622fa9e4066Sahrens 623e9dbad6fSeschrock if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed, 624fa9e4066Sahrens size)) != 0) { 625fa9e4066Sahrens kmem_free(packed, size); 626fa9e4066Sahrens return (error); 627fa9e4066Sahrens } 628fa9e4066Sahrens 629fa9e4066Sahrens if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) { 630fa9e4066Sahrens kmem_free(packed, size); 631fa9e4066Sahrens return (error); 632fa9e4066Sahrens } 633fa9e4066Sahrens 634fa9e4066Sahrens kmem_free(packed, size); 635fa9e4066Sahrens 636fa9e4066Sahrens *nvp = config; 637fa9e4066Sahrens return (0); 638fa9e4066Sahrens } 639fa9e4066Sahrens 640e9dbad6fSeschrock static int 641e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 642e9dbad6fSeschrock { 643e9dbad6fSeschrock char *packed = NULL; 644e9dbad6fSeschrock size_t size; 645e9dbad6fSeschrock int error; 646e9dbad6fSeschrock 647e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 648e9dbad6fSeschrock 649e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 650e9dbad6fSeschrock error = ENOMEM; 651e9dbad6fSeschrock } else { 652e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 653e9dbad6fSeschrock KM_SLEEP) == 0); 654e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 655e9dbad6fSeschrock size); 656e9dbad6fSeschrock kmem_free(packed, size); 657e9dbad6fSeschrock } 658e9dbad6fSeschrock 659e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 660e9dbad6fSeschrock return (error); 661e9dbad6fSeschrock } 662e9dbad6fSeschrock 663fa9e4066Sahrens static int 664fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 665fa9e4066Sahrens { 666fa9e4066Sahrens int error; 667fa9e4066Sahrens nvlist_t *config; 668fa9e4066Sahrens 669e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) != 0) 670fa9e4066Sahrens return (error); 671fa9e4066Sahrens 672e9dbad6fSeschrock error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ? 673e9dbad6fSeschrock NULL : zc->zc_value); 674fa9e4066Sahrens 675fa9e4066Sahrens nvlist_free(config); 676fa9e4066Sahrens 677fa9e4066Sahrens return (error); 678fa9e4066Sahrens } 679fa9e4066Sahrens 680fa9e4066Sahrens static int 681fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 682fa9e4066Sahrens { 683*ecd6cf80Smarks int error; 684*ecd6cf80Smarks zfs_log_history(zc); 685*ecd6cf80Smarks error = spa_destroy(zc->zc_name); 686*ecd6cf80Smarks return (error); 687fa9e4066Sahrens } 688fa9e4066Sahrens 689fa9e4066Sahrens static int 690fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 691fa9e4066Sahrens { 692fa9e4066Sahrens int error; 693fa9e4066Sahrens nvlist_t *config; 694fa9e4066Sahrens uint64_t guid; 695fa9e4066Sahrens 696e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) != 0) 697fa9e4066Sahrens return (error); 698fa9e4066Sahrens 699fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 700ea8dc4b6Seschrock guid != zc->zc_guid) 701fa9e4066Sahrens error = EINVAL; 702fa9e4066Sahrens else 703fa9e4066Sahrens error = spa_import(zc->zc_name, config, 704e9dbad6fSeschrock zc->zc_value[0] == '\0' ? NULL : zc->zc_value); 705fa9e4066Sahrens 706fa9e4066Sahrens nvlist_free(config); 707fa9e4066Sahrens 708fa9e4066Sahrens return (error); 709fa9e4066Sahrens } 710fa9e4066Sahrens 711fa9e4066Sahrens static int 712fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 713fa9e4066Sahrens { 714*ecd6cf80Smarks int error; 715*ecd6cf80Smarks zfs_log_history(zc); 716*ecd6cf80Smarks error = spa_export(zc->zc_name, NULL); 717*ecd6cf80Smarks return (error); 718fa9e4066Sahrens } 719fa9e4066Sahrens 720fa9e4066Sahrens static int 721fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 722fa9e4066Sahrens { 723fa9e4066Sahrens nvlist_t *configs; 724fa9e4066Sahrens int error; 725fa9e4066Sahrens 726fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 727fa9e4066Sahrens return (EEXIST); 728fa9e4066Sahrens 729e9dbad6fSeschrock error = put_nvlist(zc, configs); 730fa9e4066Sahrens 731fa9e4066Sahrens nvlist_free(configs); 732fa9e4066Sahrens 733fa9e4066Sahrens return (error); 734fa9e4066Sahrens } 735fa9e4066Sahrens 736fa9e4066Sahrens static int 737fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 738fa9e4066Sahrens { 739fa9e4066Sahrens nvlist_t *config; 740fa9e4066Sahrens int error; 741ea8dc4b6Seschrock int ret = 0; 742fa9e4066Sahrens 743e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 744e9dbad6fSeschrock sizeof (zc->zc_value)); 745fa9e4066Sahrens 746fa9e4066Sahrens if (config != NULL) { 747e9dbad6fSeschrock ret = put_nvlist(zc, config); 748fa9e4066Sahrens nvlist_free(config); 749ea8dc4b6Seschrock 750ea8dc4b6Seschrock /* 751ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 752ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 753ea8dc4b6Seschrock * in 'zc_cookie'. 754ea8dc4b6Seschrock */ 755ea8dc4b6Seschrock zc->zc_cookie = error; 756fa9e4066Sahrens } else { 757ea8dc4b6Seschrock ret = error; 758fa9e4066Sahrens } 759fa9e4066Sahrens 760ea8dc4b6Seschrock return (ret); 761fa9e4066Sahrens } 762fa9e4066Sahrens 763fa9e4066Sahrens /* 764fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 765fa9e4066Sahrens * user land knows which devices are available and overall pool health. 766fa9e4066Sahrens */ 767fa9e4066Sahrens static int 768fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 769fa9e4066Sahrens { 770fa9e4066Sahrens nvlist_t *tryconfig, *config; 771fa9e4066Sahrens int error; 772fa9e4066Sahrens 773e9dbad6fSeschrock if ((error = get_nvlist(zc, &tryconfig)) != 0) 774fa9e4066Sahrens return (error); 775fa9e4066Sahrens 776fa9e4066Sahrens config = spa_tryimport(tryconfig); 777fa9e4066Sahrens 778fa9e4066Sahrens nvlist_free(tryconfig); 779fa9e4066Sahrens 780fa9e4066Sahrens if (config == NULL) 781fa9e4066Sahrens return (EINVAL); 782fa9e4066Sahrens 783e9dbad6fSeschrock error = put_nvlist(zc, config); 784fa9e4066Sahrens nvlist_free(config); 785fa9e4066Sahrens 786fa9e4066Sahrens return (error); 787fa9e4066Sahrens } 788fa9e4066Sahrens 789fa9e4066Sahrens static int 790fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 791fa9e4066Sahrens { 792fa9e4066Sahrens spa_t *spa; 793fa9e4066Sahrens int error; 794fa9e4066Sahrens 79506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 79606eeb2adSek return (error); 79706eeb2adSek 7983d7072f8Seschrock spa_config_enter(spa, RW_READER, FTAG); 79906eeb2adSek error = spa_scrub(spa, zc->zc_cookie, B_FALSE); 8003d7072f8Seschrock spa_config_exit(spa, FTAG); 80106eeb2adSek 80206eeb2adSek spa_close(spa, FTAG); 80306eeb2adSek 804fa9e4066Sahrens return (error); 805fa9e4066Sahrens } 806fa9e4066Sahrens 807fa9e4066Sahrens static int 808fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 809fa9e4066Sahrens { 810fa9e4066Sahrens spa_t *spa; 811fa9e4066Sahrens int error; 812fa9e4066Sahrens 813fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 814fa9e4066Sahrens if (error == 0) { 815fa9e4066Sahrens spa_freeze(spa); 816fa9e4066Sahrens spa_close(spa, FTAG); 817fa9e4066Sahrens } 818fa9e4066Sahrens return (error); 819fa9e4066Sahrens } 820fa9e4066Sahrens 821eaca9bbdSeschrock static int 822eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 823eaca9bbdSeschrock { 824eaca9bbdSeschrock spa_t *spa; 825eaca9bbdSeschrock int error; 826eaca9bbdSeschrock 82706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 82806eeb2adSek return (error); 82906eeb2adSek 83006eeb2adSek spa_upgrade(spa); 83106eeb2adSek spa_close(spa, FTAG); 83206eeb2adSek 83306eeb2adSek return (error); 83406eeb2adSek } 83506eeb2adSek 83606eeb2adSek static int 83706eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 83806eeb2adSek { 83906eeb2adSek spa_t *spa; 84006eeb2adSek char *hist_buf; 84106eeb2adSek uint64_t size; 84206eeb2adSek int error; 84306eeb2adSek 84406eeb2adSek if ((size = zc->zc_history_len) == 0) 84506eeb2adSek return (EINVAL); 84606eeb2adSek 84706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 84806eeb2adSek return (error); 84906eeb2adSek 850d7306b64Sek if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) { 851d7306b64Sek spa_close(spa, FTAG); 852d7306b64Sek return (ENOTSUP); 853d7306b64Sek } 854d7306b64Sek 85506eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 85606eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 85706eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 858*ecd6cf80Smarks error = xcopyout(hist_buf, 859*ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 86006eeb2adSek zc->zc_history_len); 86106eeb2adSek } 86206eeb2adSek 86306eeb2adSek spa_close(spa, FTAG); 86406eeb2adSek kmem_free(hist_buf, size); 86506eeb2adSek return (error); 86606eeb2adSek } 86706eeb2adSek 86855434c77Sek static int 86955434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 87055434c77Sek { 87155434c77Sek int error; 87255434c77Sek 873b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 87455434c77Sek return (error); 87555434c77Sek 87655434c77Sek return (0); 87755434c77Sek } 87855434c77Sek 87955434c77Sek static int 88055434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 88155434c77Sek { 88255434c77Sek objset_t *osp; 88355434c77Sek int error; 88455434c77Sek 88555434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 88655434c77Sek DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) 88755434c77Sek return (error); 88855434c77Sek 88955434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 89055434c77Sek sizeof (zc->zc_value)); 89155434c77Sek dmu_objset_close(osp); 89255434c77Sek 89355434c77Sek return (error); 89455434c77Sek } 89555434c77Sek 896fa9e4066Sahrens static int 897fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 898fa9e4066Sahrens { 899fa9e4066Sahrens spa_t *spa; 900fa9e4066Sahrens int error; 901fa9e4066Sahrens nvlist_t *config; 902fa9e4066Sahrens 903fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 904fa9e4066Sahrens if (error != 0) 905fa9e4066Sahrens return (error); 906fa9e4066Sahrens 907b1b8ab34Slling /* 908b1b8ab34Slling * A root pool with concatenated devices is not supported. 909b1b8ab34Slling * Thus, can not add a device to a root pool with one device. 910b1b8ab34Slling */ 911b1b8ab34Slling if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) { 912b1b8ab34Slling spa_close(spa, FTAG); 913b1b8ab34Slling return (EDOM); 914b1b8ab34Slling } 915b1b8ab34Slling 916e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) == 0) { 917fa9e4066Sahrens error = spa_vdev_add(spa, config); 918fa9e4066Sahrens nvlist_free(config); 919fa9e4066Sahrens } 920fa9e4066Sahrens spa_close(spa, FTAG); 921fa9e4066Sahrens return (error); 922fa9e4066Sahrens } 923fa9e4066Sahrens 924fa9e4066Sahrens static int 925fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 926fa9e4066Sahrens { 92799653d4eSeschrock spa_t *spa; 92899653d4eSeschrock int error; 92999653d4eSeschrock 93099653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 93199653d4eSeschrock if (error != 0) 93299653d4eSeschrock return (error); 93399653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 93499653d4eSeschrock spa_close(spa, FTAG); 93599653d4eSeschrock return (error); 936fa9e4066Sahrens } 937fa9e4066Sahrens 938fa9e4066Sahrens static int 9393d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 940fa9e4066Sahrens { 941fa9e4066Sahrens spa_t *spa; 942fa9e4066Sahrens int error; 9433d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 944fa9e4066Sahrens 94506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 946fa9e4066Sahrens return (error); 9473d7072f8Seschrock switch (zc->zc_cookie) { 9483d7072f8Seschrock case VDEV_STATE_ONLINE: 9493d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 9503d7072f8Seschrock break; 951fa9e4066Sahrens 9523d7072f8Seschrock case VDEV_STATE_OFFLINE: 9533d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 9543d7072f8Seschrock break; 955fa9e4066Sahrens 9563d7072f8Seschrock case VDEV_STATE_FAULTED: 9573d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 9583d7072f8Seschrock break; 9593d7072f8Seschrock 9603d7072f8Seschrock case VDEV_STATE_DEGRADED: 9613d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 9623d7072f8Seschrock break; 9633d7072f8Seschrock 9643d7072f8Seschrock default: 9653d7072f8Seschrock error = EINVAL; 9663d7072f8Seschrock } 9673d7072f8Seschrock zc->zc_cookie = newstate; 968fa9e4066Sahrens spa_close(spa, FTAG); 969fa9e4066Sahrens return (error); 970fa9e4066Sahrens } 971fa9e4066Sahrens 972fa9e4066Sahrens static int 973fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 974fa9e4066Sahrens { 975fa9e4066Sahrens spa_t *spa; 976fa9e4066Sahrens int replacing = zc->zc_cookie; 977fa9e4066Sahrens nvlist_t *config; 978fa9e4066Sahrens int error; 979fa9e4066Sahrens 98006eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 981fa9e4066Sahrens return (error); 982fa9e4066Sahrens 983e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) == 0) { 984ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 985fa9e4066Sahrens nvlist_free(config); 986fa9e4066Sahrens } 987fa9e4066Sahrens 988fa9e4066Sahrens spa_close(spa, FTAG); 989fa9e4066Sahrens return (error); 990fa9e4066Sahrens } 991fa9e4066Sahrens 992fa9e4066Sahrens static int 993fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 994fa9e4066Sahrens { 995fa9e4066Sahrens spa_t *spa; 996fa9e4066Sahrens int error; 997fa9e4066Sahrens 99806eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 999fa9e4066Sahrens return (error); 1000fa9e4066Sahrens 1001ea8dc4b6Seschrock error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 1002fa9e4066Sahrens 1003fa9e4066Sahrens spa_close(spa, FTAG); 1004fa9e4066Sahrens return (error); 1005fa9e4066Sahrens } 1006fa9e4066Sahrens 1007c67d9675Seschrock static int 1008c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1009c67d9675Seschrock { 1010c67d9675Seschrock spa_t *spa; 1011e9dbad6fSeschrock char *path = zc->zc_value; 1012ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1013c67d9675Seschrock int error; 1014c67d9675Seschrock 1015c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1016c67d9675Seschrock if (error != 0) 1017c67d9675Seschrock return (error); 1018c67d9675Seschrock 1019c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1020c67d9675Seschrock spa_close(spa, FTAG); 1021c67d9675Seschrock return (error); 1022c67d9675Seschrock } 1023c67d9675Seschrock 1024fa9e4066Sahrens static int 1025fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1026fa9e4066Sahrens { 1027fa9e4066Sahrens objset_t *os = NULL; 1028fa9e4066Sahrens int error; 10297f7322feSeschrock nvlist_t *nv; 1030fa9e4066Sahrens 1031fa9e4066Sahrens retry: 1032fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1033fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 1034fa9e4066Sahrens if (error != 0) { 1035fa9e4066Sahrens /* 1036fa9e4066Sahrens * This is ugly: dmu_objset_open() can return EBUSY if 1037fa9e4066Sahrens * the objset is held exclusively. Fortunately this hold is 1038fa9e4066Sahrens * only for a short while, so we retry here. 1039fa9e4066Sahrens * This avoids user code having to handle EBUSY, 1040fa9e4066Sahrens * for example for a "zfs list". 1041fa9e4066Sahrens */ 1042fa9e4066Sahrens if (error == EBUSY) { 1043fa9e4066Sahrens delay(1); 1044fa9e4066Sahrens goto retry; 1045fa9e4066Sahrens } 1046fa9e4066Sahrens return (error); 1047fa9e4066Sahrens } 1048fa9e4066Sahrens 1049a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1050fa9e4066Sahrens 10515ad82045Snd if (zc->zc_nvlist_dst != 0 && 10527f7322feSeschrock (error = dsl_prop_get_all(os, &nv)) == 0) { 1053a2eea2e1Sahrens dmu_objset_stats(os, nv); 1054432f72fdSahrens /* 1055432f72fdSahrens * NB: zvol_get_stats() will read the objset contents, 1056432f72fdSahrens * which we aren't supposed to do with a 1057432f72fdSahrens * DS_MODE_STANDARD open, because it could be 1058432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1059432f72fdSahrens */ 1060432f72fdSahrens if (!zc->zc_objset_stats.dds_inconsistent && 1061432f72fdSahrens dmu_objset_type(os) == DMU_OST_ZVOL) 1062a2eea2e1Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1063e9dbad6fSeschrock error = put_nvlist(zc, nv); 10647f7322feSeschrock nvlist_free(nv); 10657f7322feSeschrock } 1066fa9e4066Sahrens 1067e9dbad6fSeschrock spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); 1068ea8dc4b6Seschrock 1069fa9e4066Sahrens dmu_objset_close(os); 1070fa9e4066Sahrens return (error); 1071fa9e4066Sahrens } 1072fa9e4066Sahrens 1073fa9e4066Sahrens static int 1074fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1075fa9e4066Sahrens { 107687e5029aSahrens objset_t *os; 1077fa9e4066Sahrens int error; 1078fa9e4066Sahrens char *p; 1079fa9e4066Sahrens 108087e5029aSahrens retry: 108187e5029aSahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 108287e5029aSahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 108387e5029aSahrens if (error != 0) { 108487e5029aSahrens /* 108587e5029aSahrens * This is ugly: dmu_objset_open() can return EBUSY if 108687e5029aSahrens * the objset is held exclusively. Fortunately this hold is 108787e5029aSahrens * only for a short while, so we retry here. 108887e5029aSahrens * This avoids user code having to handle EBUSY, 108987e5029aSahrens * for example for a "zfs list". 109087e5029aSahrens */ 109187e5029aSahrens if (error == EBUSY) { 109287e5029aSahrens delay(1); 109387e5029aSahrens goto retry; 109487e5029aSahrens } 109587e5029aSahrens if (error == ENOENT) 109687e5029aSahrens error = ESRCH; 109787e5029aSahrens return (error); 1098fa9e4066Sahrens } 1099fa9e4066Sahrens 1100fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1101fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1102fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1103fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1104fa9e4066Sahrens 1105fa9e4066Sahrens do { 110687e5029aSahrens error = dmu_dir_list_next(os, 110787e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 110887e5029aSahrens NULL, &zc->zc_cookie); 1109fa9e4066Sahrens if (error == ENOENT) 1110fa9e4066Sahrens error = ESRCH; 111187e5029aSahrens } while (error == 0 && !INGLOBALZONE(curproc) && 1112fa9e4066Sahrens !zone_dataset_visible(zc->zc_name, NULL)); 1113fa9e4066Sahrens 1114fa9e4066Sahrens /* 111587e5029aSahrens * If it's a hidden dataset (ie. with a '$' in its name), don't 111687e5029aSahrens * try to get stats for it. Userland will skip over it. 1117fa9e4066Sahrens */ 111887e5029aSahrens if (error == 0 && strchr(zc->zc_name, '$') == NULL) 111987e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1120fa9e4066Sahrens 112187e5029aSahrens dmu_objset_close(os); 1122fa9e4066Sahrens return (error); 1123fa9e4066Sahrens } 1124fa9e4066Sahrens 1125fa9e4066Sahrens static int 1126fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1127fa9e4066Sahrens { 112887e5029aSahrens objset_t *os; 1129fa9e4066Sahrens int error; 1130fa9e4066Sahrens 1131fa9e4066Sahrens retry: 113287e5029aSahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 113387e5029aSahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 113487e5029aSahrens if (error != 0) { 1135fa9e4066Sahrens /* 113687e5029aSahrens * This is ugly: dmu_objset_open() can return EBUSY if 1137fa9e4066Sahrens * the objset is held exclusively. Fortunately this hold is 1138fa9e4066Sahrens * only for a short while, so we retry here. 1139fa9e4066Sahrens * This avoids user code having to handle EBUSY, 114087e5029aSahrens * for example for a "zfs list". 1141fa9e4066Sahrens */ 1142fa9e4066Sahrens if (error == EBUSY) { 1143fa9e4066Sahrens delay(1); 1144fa9e4066Sahrens goto retry; 1145fa9e4066Sahrens } 1146fa9e4066Sahrens if (error == ENOENT) 114787e5029aSahrens error = ESRCH; 1148fa9e4066Sahrens return (error); 1149fa9e4066Sahrens } 1150fa9e4066Sahrens 1151b81d61a6Slling /* 1152b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1153b81d61a6Slling * so exit immediately. 1154b81d61a6Slling */ 1155b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 115687e5029aSahrens dmu_objset_close(os); 1157b81d61a6Slling return (ESRCH); 1158fa9e4066Sahrens } 1159fa9e4066Sahrens 116087e5029aSahrens error = dmu_snapshot_list_next(os, 116187e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 116287e5029aSahrens zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); 116387e5029aSahrens if (error == ENOENT) 116487e5029aSahrens error = ESRCH; 1165fa9e4066Sahrens 116687e5029aSahrens if (error == 0) 116787e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1168fa9e4066Sahrens 116987e5029aSahrens dmu_objset_close(os); 1170fa9e4066Sahrens return (error); 1171fa9e4066Sahrens } 1172fa9e4066Sahrens 1173fa9e4066Sahrens static int 1174e9dbad6fSeschrock zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) 1175fa9e4066Sahrens { 1176e9dbad6fSeschrock nvpair_t *elem; 1177e9dbad6fSeschrock int error; 1178e9dbad6fSeschrock const char *propname; 1179e9dbad6fSeschrock zfs_prop_t prop; 1180e9dbad6fSeschrock uint64_t intval; 1181e9dbad6fSeschrock char *strval; 1182e9dbad6fSeschrock 1183*ecd6cf80Smarks /* 1184*ecd6cf80Smarks * First validate permission to set all of the properties 1185*ecd6cf80Smarks */ 1186e9dbad6fSeschrock elem = NULL; 1187e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1188e9dbad6fSeschrock propname = nvpair_name(elem); 1189e9dbad6fSeschrock 1190e9dbad6fSeschrock if ((prop = zfs_name_to_prop(propname)) == 1191e9dbad6fSeschrock ZFS_PROP_INVAL) { 1192e9dbad6fSeschrock /* 1193e9dbad6fSeschrock * If this is a user-defined property, it must be a 1194e9dbad6fSeschrock * string, and there is no further validation to do. 1195e9dbad6fSeschrock */ 1196e9dbad6fSeschrock if (!zfs_prop_user(propname) || 1197e9dbad6fSeschrock nvpair_type(elem) != DATA_TYPE_STRING) 1198e9dbad6fSeschrock return (EINVAL); 1199e9dbad6fSeschrock 1200*ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 1201*ecd6cf80Smarks ZFS_DELEG_PERM_USERPROP, cr); 1202*ecd6cf80Smarks if (error) { 1203*ecd6cf80Smarks return (EPERM); 1204*ecd6cf80Smarks } 1205*ecd6cf80Smarks continue; 1206e9dbad6fSeschrock } 1207fa9e4066Sahrens 1208e9dbad6fSeschrock /* 1209*ecd6cf80Smarks * Check permissions for special properties 1210e9dbad6fSeschrock */ 1211*ecd6cf80Smarks 1212e9dbad6fSeschrock switch (prop) { 1213e9dbad6fSeschrock case ZFS_PROP_ZONED: 1214e9dbad6fSeschrock /* 1215e9dbad6fSeschrock * Disallow setting of 'zoned' from within a local zone. 1216e9dbad6fSeschrock */ 1217e9dbad6fSeschrock if (!INGLOBALZONE(curproc)) 1218e9dbad6fSeschrock return (EPERM); 1219e9dbad6fSeschrock break; 1220fa9e4066Sahrens 1221e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1222e9dbad6fSeschrock if (error = zfs_dozonecheck(name, cr)) 1223e9dbad6fSeschrock return (error); 1224fa9e4066Sahrens 1225e9dbad6fSeschrock if (!INGLOBALZONE(curproc)) { 1226e9dbad6fSeschrock uint64_t zoned; 1227e9dbad6fSeschrock char setpoint[MAXNAMELEN]; 1228e9dbad6fSeschrock int dslen; 1229e9dbad6fSeschrock /* 1230e9dbad6fSeschrock * Unprivileged users are allowed to modify the 1231e9dbad6fSeschrock * quota on things *under* (ie. contained by) 1232e9dbad6fSeschrock * the thing they own. 1233e9dbad6fSeschrock */ 1234e9dbad6fSeschrock if (dsl_prop_get_integer(name, "zoned", &zoned, 1235e9dbad6fSeschrock setpoint)) 1236e9dbad6fSeschrock return (EPERM); 1237e9dbad6fSeschrock if (!zoned) /* this shouldn't happen */ 1238e9dbad6fSeschrock return (EPERM); 1239e9dbad6fSeschrock dslen = strlen(name); 1240e9dbad6fSeschrock if (dslen <= strlen(setpoint)) 1241e9dbad6fSeschrock return (EPERM); 1242e9dbad6fSeschrock } 1243c9431fa1Sahl break; 1244c9431fa1Sahl 1245c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1246c9431fa1Sahl /* 1247c9431fa1Sahl * If the user specified gzip compression, make sure 1248c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1249c9431fa1Sahl * we'll catch them later. 1250c9431fa1Sahl */ 1251c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1252c9431fa1Sahl nvpair_value_uint64(elem, &intval) == 0 && 1253c9431fa1Sahl intval >= ZIO_COMPRESS_GZIP_1 && 1254c9431fa1Sahl intval <= ZIO_COMPRESS_GZIP_9) { 1255*ecd6cf80Smarks char buf[MAXNAMELEN]; 1256*ecd6cf80Smarks spa_t *spa; 1257*ecd6cf80Smarks const char *p; 1258*ecd6cf80Smarks 1259c9431fa1Sahl if ((p = strchr(name, '/')) == NULL) { 1260c9431fa1Sahl p = name; 1261c9431fa1Sahl } else { 1262c9431fa1Sahl bcopy(name, buf, p - name); 1263c9431fa1Sahl buf[p - name] = '\0'; 1264c9431fa1Sahl p = buf; 1265c9431fa1Sahl } 1266c9431fa1Sahl 1267c9431fa1Sahl if (spa_open(p, &spa, FTAG) == 0) { 1268c9431fa1Sahl if (spa_version(spa) < 1269c9431fa1Sahl ZFS_VERSION_GZIP_COMPRESSION) { 1270c9431fa1Sahl spa_close(spa, FTAG); 1271c9431fa1Sahl return (ENOTSUP); 1272c9431fa1Sahl } 1273c9431fa1Sahl 1274c9431fa1Sahl spa_close(spa, FTAG); 1275c9431fa1Sahl } 1276c9431fa1Sahl } 1277c9431fa1Sahl break; 1278e9dbad6fSeschrock } 1279*ecd6cf80Smarks if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0) 1280*ecd6cf80Smarks return (error); 1281*ecd6cf80Smarks } 1282*ecd6cf80Smarks 1283*ecd6cf80Smarks elem = NULL; 1284*ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1285*ecd6cf80Smarks propname = nvpair_name(elem); 1286*ecd6cf80Smarks 1287*ecd6cf80Smarks if ((prop = zfs_name_to_prop(propname)) == 1288*ecd6cf80Smarks ZFS_PROP_INVAL) { 1289*ecd6cf80Smarks 1290*ecd6cf80Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 1291*ecd6cf80Smarks error = dsl_prop_set(name, propname, 1, 1292*ecd6cf80Smarks strlen(strval) + 1, strval); 1293*ecd6cf80Smarks if (error == 0) 1294*ecd6cf80Smarks continue; 1295*ecd6cf80Smarks else 1296*ecd6cf80Smarks return (error); 1297*ecd6cf80Smarks } 1298e9dbad6fSeschrock 1299e9dbad6fSeschrock switch (prop) { 1300e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1301e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1302e9dbad6fSeschrock (error = dsl_dir_set_quota(name, 1303e9dbad6fSeschrock intval)) != 0) 1304e9dbad6fSeschrock return (error); 1305e9dbad6fSeschrock break; 1306e9dbad6fSeschrock 1307e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1308e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1309e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1310e9dbad6fSeschrock intval)) != 0) 1311e9dbad6fSeschrock return (error); 1312e9dbad6fSeschrock break; 1313e9dbad6fSeschrock 1314e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1315e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1316e9dbad6fSeschrock (error = zvol_set_volsize(name, dev, 1317e9dbad6fSeschrock intval)) != 0) 1318e9dbad6fSeschrock return (error); 1319e9dbad6fSeschrock break; 1320e9dbad6fSeschrock 1321e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1322e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1323e9dbad6fSeschrock (error = zvol_set_volblocksize(name, 1324e9dbad6fSeschrock intval)) != 0) 1325e9dbad6fSeschrock return (error); 1326e9dbad6fSeschrock break; 1327e9dbad6fSeschrock 1328e9dbad6fSeschrock default: 1329e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1330e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 1331e9dbad6fSeschrock prop_type_string) 1332e9dbad6fSeschrock return (EINVAL); 1333acd76fe5Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 1334acd76fe5Seschrock if ((error = dsl_prop_set(name, 1335e9dbad6fSeschrock nvpair_name(elem), 1, strlen(strval) + 1, 1336acd76fe5Seschrock strval)) != 0) 1337acd76fe5Seschrock return (error); 1338e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1339a2eea2e1Sahrens const char *unused; 1340a2eea2e1Sahrens 1341acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1342e9dbad6fSeschrock 1343e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 1344e9dbad6fSeschrock case prop_type_number: 1345e9dbad6fSeschrock break; 1346e9dbad6fSeschrock case prop_type_boolean: 1347e9dbad6fSeschrock if (intval > 1) 1348acd76fe5Seschrock return (EINVAL); 1349e9dbad6fSeschrock break; 1350e9dbad6fSeschrock case prop_type_string: 1351acd76fe5Seschrock return (EINVAL); 1352e9dbad6fSeschrock case prop_type_index: 1353acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 1354acd76fe5Seschrock intval, &unused) != 0) 1355acd76fe5Seschrock return (EINVAL); 1356e9dbad6fSeschrock break; 1357e9dbad6fSeschrock default: 1358e9dbad6fSeschrock cmn_err(CE_PANIC, "unknown property " 1359e9dbad6fSeschrock "type"); 1360e9dbad6fSeschrock break; 1361e9dbad6fSeschrock } 1362e9dbad6fSeschrock 1363acd76fe5Seschrock if ((error = dsl_prop_set(name, propname, 1364acd76fe5Seschrock 8, 1, &intval)) != 0) 1365acd76fe5Seschrock return (error); 1366e9dbad6fSeschrock } else { 1367e9dbad6fSeschrock return (EINVAL); 1368e9dbad6fSeschrock } 1369e9dbad6fSeschrock break; 1370e9dbad6fSeschrock } 1371e9dbad6fSeschrock } 1372e9dbad6fSeschrock 1373e9dbad6fSeschrock return (0); 1374fa9e4066Sahrens } 1375fa9e4066Sahrens 1376fa9e4066Sahrens static int 1377e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1378fa9e4066Sahrens { 1379e9dbad6fSeschrock nvlist_t *nvl; 1380e9dbad6fSeschrock int error; 1381e9dbad6fSeschrock zfs_prop_t prop; 1382e9dbad6fSeschrock 1383e9dbad6fSeschrock /* 1384e9dbad6fSeschrock * If zc_value is set, then this is an attempt to inherit a value. 1385e9dbad6fSeschrock * Otherwise, zc_nvlist refers to a list of properties to set. 1386e9dbad6fSeschrock */ 1387e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1388e9dbad6fSeschrock if (!zfs_prop_user(zc->zc_value) && 1389e9dbad6fSeschrock ((prop = zfs_name_to_prop(zc->zc_value)) == 1390e9dbad6fSeschrock ZFS_PROP_INVAL || 1391e9dbad6fSeschrock !zfs_prop_inheritable(prop))) 1392e9dbad6fSeschrock return (EINVAL); 1393e9dbad6fSeschrock 1394e9dbad6fSeschrock return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1395e9dbad6fSeschrock } 1396e9dbad6fSeschrock 1397e9dbad6fSeschrock if ((error = get_nvlist(zc, &nvl)) != 0) 1398e9dbad6fSeschrock return (error); 1399e9dbad6fSeschrock 1400e9dbad6fSeschrock error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev, 1401e9dbad6fSeschrock (cred_t *)(uintptr_t)zc->zc_cred, nvl); 1402*ecd6cf80Smarks 1403e9dbad6fSeschrock nvlist_free(nvl); 1404e9dbad6fSeschrock return (error); 1405fa9e4066Sahrens } 1406fa9e4066Sahrens 1407b1b8ab34Slling static int 140811a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1409b1b8ab34Slling { 1410b1b8ab34Slling nvlist_t *nvl; 1411b1b8ab34Slling int error, reset_bootfs = 0; 1412b1b8ab34Slling uint64_t objnum; 1413*ecd6cf80Smarks uint64_t intval; 1414b1b8ab34Slling zpool_prop_t prop; 1415b1b8ab34Slling nvpair_t *elem; 1416b1b8ab34Slling char *propname, *strval; 1417b1b8ab34Slling spa_t *spa; 1418b1b8ab34Slling vdev_t *rvdev; 1419b1b8ab34Slling char *vdev_type; 1420b1b8ab34Slling objset_t *os; 1421b1b8ab34Slling 1422b1b8ab34Slling if ((error = get_nvlist(zc, &nvl)) != 0) 1423b1b8ab34Slling return (error); 1424b1b8ab34Slling 1425b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1426b1b8ab34Slling nvlist_free(nvl); 1427b1b8ab34Slling return (error); 1428b1b8ab34Slling } 1429b1b8ab34Slling 1430b1b8ab34Slling if (spa_version(spa) < ZFS_VERSION_BOOTFS) { 1431b1b8ab34Slling nvlist_free(nvl); 1432b1b8ab34Slling spa_close(spa, FTAG); 1433b1b8ab34Slling return (ENOTSUP); 1434b1b8ab34Slling } 1435b1b8ab34Slling 1436b1b8ab34Slling elem = NULL; 1437b1b8ab34Slling while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1438b1b8ab34Slling 1439b1b8ab34Slling propname = nvpair_name(elem); 1440b1b8ab34Slling 1441b1b8ab34Slling if ((prop = zpool_name_to_prop(propname)) == 1442b1b8ab34Slling ZFS_PROP_INVAL) { 1443b1b8ab34Slling nvlist_free(nvl); 1444b1b8ab34Slling spa_close(spa, FTAG); 1445b1b8ab34Slling return (EINVAL); 1446b1b8ab34Slling } 1447b1b8ab34Slling 1448b1b8ab34Slling switch (prop) { 1449*ecd6cf80Smarks case ZPOOL_PROP_DELEGATION: 1450*ecd6cf80Smarks VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1451*ecd6cf80Smarks if (intval > 1) 1452*ecd6cf80Smarks error = EINVAL; 1453*ecd6cf80Smarks break; 14543d7072f8Seschrock case ZPOOL_PROP_BOOTFS: 1455b1b8ab34Slling /* 1456b1b8ab34Slling * A bootable filesystem can not be on a RAIDZ pool 1457b1b8ab34Slling * nor a striped pool with more than 1 device. 1458b1b8ab34Slling */ 1459b1b8ab34Slling rvdev = spa->spa_root_vdev; 1460b1b8ab34Slling vdev_type = 1461b1b8ab34Slling rvdev->vdev_child[0]->vdev_ops->vdev_op_type; 1462b1b8ab34Slling if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 || 1463b1b8ab34Slling (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 && 1464b1b8ab34Slling rvdev->vdev_children > 1)) { 1465b1b8ab34Slling error = ENOTSUP; 1466b1b8ab34Slling break; 1467b1b8ab34Slling } 1468b1b8ab34Slling 1469b1b8ab34Slling reset_bootfs = 1; 1470b1b8ab34Slling 1471b1b8ab34Slling VERIFY(nvpair_value_string(elem, &strval) == 0); 1472b1b8ab34Slling if (strval == NULL || strval[0] == '\0') { 14733d7072f8Seschrock objnum = zpool_prop_default_numeric( 14743d7072f8Seschrock ZPOOL_PROP_BOOTFS); 1475b1b8ab34Slling break; 1476b1b8ab34Slling } 1477b1b8ab34Slling 1478b1b8ab34Slling if (error = dmu_objset_open(strval, DMU_OST_ZFS, 1479b1b8ab34Slling DS_MODE_STANDARD | DS_MODE_READONLY, &os)) 1480b1b8ab34Slling break; 1481b1b8ab34Slling objnum = dmu_objset_id(os); 1482b1b8ab34Slling dmu_objset_close(os); 1483b1b8ab34Slling break; 1484b1b8ab34Slling } 1485b1b8ab34Slling 1486b1b8ab34Slling if (error) 1487b1b8ab34Slling break; 1488b1b8ab34Slling } 1489b1b8ab34Slling if (error == 0) { 1490b1b8ab34Slling if (reset_bootfs) { 1491b1b8ab34Slling VERIFY(nvlist_remove(nvl, 14923d7072f8Seschrock zpool_prop_to_name(ZPOOL_PROP_BOOTFS), 1493b1b8ab34Slling DATA_TYPE_STRING) == 0); 1494b1b8ab34Slling VERIFY(nvlist_add_uint64(nvl, 14953d7072f8Seschrock zpool_prop_to_name(ZPOOL_PROP_BOOTFS), 14963d7072f8Seschrock objnum) == 0); 1497b1b8ab34Slling } 1498b1b8ab34Slling error = spa_set_props(spa, nvl); 1499b1b8ab34Slling } 1500b1b8ab34Slling 1501b1b8ab34Slling nvlist_free(nvl); 1502b1b8ab34Slling spa_close(spa, FTAG); 1503b1b8ab34Slling 1504b1b8ab34Slling return (error); 1505b1b8ab34Slling } 1506b1b8ab34Slling 1507b1b8ab34Slling static int 150811a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1509b1b8ab34Slling { 1510b1b8ab34Slling spa_t *spa; 1511b1b8ab34Slling int error; 1512b1b8ab34Slling nvlist_t *nvp = NULL; 1513b1b8ab34Slling 1514b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1515b1b8ab34Slling return (error); 1516b1b8ab34Slling 1517b1b8ab34Slling error = spa_get_props(spa, &nvp); 1518b1b8ab34Slling 1519b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1520b1b8ab34Slling error = put_nvlist(zc, nvp); 1521b1b8ab34Slling else 1522b1b8ab34Slling error = EFAULT; 1523b1b8ab34Slling 1524b1b8ab34Slling spa_close(spa, FTAG); 1525b1b8ab34Slling 1526b1b8ab34Slling if (nvp) 1527b1b8ab34Slling nvlist_free(nvp); 1528b1b8ab34Slling return (error); 1529b1b8ab34Slling } 1530b1b8ab34Slling 1531*ecd6cf80Smarks static int 1532*ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1533*ecd6cf80Smarks { 1534*ecd6cf80Smarks nvlist_t *nvp; 1535*ecd6cf80Smarks int error; 1536*ecd6cf80Smarks uint32_t uid; 1537*ecd6cf80Smarks uint32_t gid; 1538*ecd6cf80Smarks uint32_t *groups; 1539*ecd6cf80Smarks uint_t group_cnt; 1540*ecd6cf80Smarks cred_t *usercred; 1541*ecd6cf80Smarks 1542*ecd6cf80Smarks if ((error = get_nvlist(zc, &nvp)) != 0) { 1543*ecd6cf80Smarks return (error); 1544*ecd6cf80Smarks } 1545*ecd6cf80Smarks 1546*ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1547*ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 1548*ecd6cf80Smarks nvlist_free(nvp); 1549*ecd6cf80Smarks return (EPERM); 1550*ecd6cf80Smarks } 1551*ecd6cf80Smarks 1552*ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1553*ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 1554*ecd6cf80Smarks nvlist_free(nvp); 1555*ecd6cf80Smarks return (EPERM); 1556*ecd6cf80Smarks } 1557*ecd6cf80Smarks 1558*ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1559*ecd6cf80Smarks &groups, &group_cnt)) != 0) { 1560*ecd6cf80Smarks nvlist_free(nvp); 1561*ecd6cf80Smarks return (EPERM); 1562*ecd6cf80Smarks } 1563*ecd6cf80Smarks usercred = cralloc(); 1564*ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 1565*ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1566*ecd6cf80Smarks nvlist_free(nvp); 1567*ecd6cf80Smarks crfree(usercred); 1568*ecd6cf80Smarks return (EPERM); 1569*ecd6cf80Smarks } 1570*ecd6cf80Smarks nvlist_free(nvp); 1571*ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 1572*ecd6cf80Smarks ZFS_DELEG_PERM_SHAREISCSI, usercred); 1573*ecd6cf80Smarks crfree(usercred); 1574*ecd6cf80Smarks return (error); 1575*ecd6cf80Smarks } 1576*ecd6cf80Smarks 1577*ecd6cf80Smarks static int 1578*ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 1579*ecd6cf80Smarks { 1580*ecd6cf80Smarks int error; 1581*ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 1582*ecd6cf80Smarks cred_t *cr; 1583*ecd6cf80Smarks 1584*ecd6cf80Smarks if ((error = get_nvlist(zc, &fsaclnv)) != 0) 1585*ecd6cf80Smarks return (error); 1586*ecd6cf80Smarks 1587*ecd6cf80Smarks /* 1588*ecd6cf80Smarks * Verify nvlist is constructed correctly 1589*ecd6cf80Smarks */ 1590*ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1591*ecd6cf80Smarks nvlist_free(fsaclnv); 1592*ecd6cf80Smarks return (EINVAL); 1593*ecd6cf80Smarks } 1594*ecd6cf80Smarks 1595*ecd6cf80Smarks /* 1596*ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 1597*ecd6cf80Smarks * that user is allowed to hand out each permission in 1598*ecd6cf80Smarks * the nvlist(s) 1599*ecd6cf80Smarks */ 1600*ecd6cf80Smarks 1601*ecd6cf80Smarks cr = (cred_t *)(uintptr_t)zc->zc_cred; 1602*ecd6cf80Smarks error = secpolicy_zfs(cr); 1603*ecd6cf80Smarks if (error) { 1604*ecd6cf80Smarks if (zc->zc_perm_action == B_FALSE) 1605*ecd6cf80Smarks error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr); 1606*ecd6cf80Smarks else 1607*ecd6cf80Smarks error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr); 1608*ecd6cf80Smarks } 1609*ecd6cf80Smarks 1610*ecd6cf80Smarks if (error == 0) 1611*ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1612*ecd6cf80Smarks 1613*ecd6cf80Smarks nvlist_free(fsaclnv); 1614*ecd6cf80Smarks return (error); 1615*ecd6cf80Smarks } 1616*ecd6cf80Smarks 1617*ecd6cf80Smarks static int 1618*ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 1619*ecd6cf80Smarks { 1620*ecd6cf80Smarks nvlist_t *nvp; 1621*ecd6cf80Smarks int error; 1622*ecd6cf80Smarks 1623*ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1624*ecd6cf80Smarks error = put_nvlist(zc, nvp); 1625*ecd6cf80Smarks nvlist_free(nvp); 1626*ecd6cf80Smarks } 1627*ecd6cf80Smarks 1628*ecd6cf80Smarks return (error); 1629*ecd6cf80Smarks } 1630*ecd6cf80Smarks 1631fa9e4066Sahrens static int 1632fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1633fa9e4066Sahrens { 1634e9dbad6fSeschrock return (zvol_create_minor(zc->zc_name, zc->zc_dev)); 1635fa9e4066Sahrens } 1636fa9e4066Sahrens 1637fa9e4066Sahrens static int 1638fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1639fa9e4066Sahrens { 1640e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 1641fa9e4066Sahrens } 1642fa9e4066Sahrens 1643fa9e4066Sahrens /* 1644fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1645fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 1646fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 1647fa9e4066Sahrens */ 1648fa9e4066Sahrens static vfs_t * 1649fa9e4066Sahrens zfs_get_vfs(const char *resource) 1650fa9e4066Sahrens { 1651fa9e4066Sahrens struct vfs *vfsp; 1652fa9e4066Sahrens struct vfs *vfs_found = NULL; 1653fa9e4066Sahrens 1654fa9e4066Sahrens vfs_list_read_lock(); 1655fa9e4066Sahrens vfsp = rootvfs; 1656fa9e4066Sahrens do { 1657fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1658fa9e4066Sahrens VFS_HOLD(vfsp); 1659fa9e4066Sahrens vfs_found = vfsp; 1660fa9e4066Sahrens break; 1661fa9e4066Sahrens } 1662fa9e4066Sahrens vfsp = vfsp->vfs_next; 1663fa9e4066Sahrens } while (vfsp != rootvfs); 1664fa9e4066Sahrens vfs_list_unlock(); 1665fa9e4066Sahrens return (vfs_found); 1666fa9e4066Sahrens } 1667fa9e4066Sahrens 1668*ecd6cf80Smarks /* ARGSUSED */ 1669fa9e4066Sahrens static void 1670*ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1671fa9e4066Sahrens { 1672*ecd6cf80Smarks zfs_create_fs(os, cr, tx); 1673fa9e4066Sahrens } 1674fa9e4066Sahrens 1675fa9e4066Sahrens static int 1676fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 1677fa9e4066Sahrens { 1678fa9e4066Sahrens objset_t *clone; 1679fa9e4066Sahrens int error = 0; 1680*ecd6cf80Smarks nvlist_t *nvprops = NULL; 1681*ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 1682fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 1683fa9e4066Sahrens 1684fa9e4066Sahrens switch (type) { 1685fa9e4066Sahrens 1686fa9e4066Sahrens case DMU_OST_ZFS: 1687fa9e4066Sahrens cbfunc = zfs_create_cb; 1688fa9e4066Sahrens break; 1689fa9e4066Sahrens 1690fa9e4066Sahrens case DMU_OST_ZVOL: 1691fa9e4066Sahrens cbfunc = zvol_create_cb; 1692fa9e4066Sahrens break; 1693fa9e4066Sahrens 1694fa9e4066Sahrens default: 16951d452cf5Sahrens cbfunc = NULL; 1696fa9e4066Sahrens } 16971d452cf5Sahrens if (strchr(zc->zc_name, '@')) 16981d452cf5Sahrens return (EINVAL); 1699fa9e4066Sahrens 1700e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 1701*ecd6cf80Smarks (error = get_nvlist(zc, &nvprops)) != 0) 1702e9dbad6fSeschrock return (error); 1703e9dbad6fSeschrock 1704e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1705fa9e4066Sahrens /* 1706fa9e4066Sahrens * We're creating a clone of an existing snapshot. 1707fa9e4066Sahrens */ 1708e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1709e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 1710*ecd6cf80Smarks nvlist_free(nvprops); 1711fa9e4066Sahrens return (EINVAL); 1712e9dbad6fSeschrock } 1713fa9e4066Sahrens 1714e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 1715fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 1716e9dbad6fSeschrock if (error) { 1717*ecd6cf80Smarks nvlist_free(nvprops); 1718fa9e4066Sahrens return (error); 1719e9dbad6fSeschrock } 1720fa9e4066Sahrens error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); 1721fa9e4066Sahrens dmu_objset_close(clone); 1722fa9e4066Sahrens } else { 1723e9dbad6fSeschrock if (cbfunc == NULL) { 1724*ecd6cf80Smarks nvlist_free(nvprops); 17251d452cf5Sahrens return (EINVAL); 1726e9dbad6fSeschrock } 17275c5460e9Seschrock 1728e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 1729e9dbad6fSeschrock uint64_t volsize, volblocksize; 1730e9dbad6fSeschrock 1731*ecd6cf80Smarks if (nvprops == NULL || 1732*ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 1733e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1734e9dbad6fSeschrock &volsize) != 0) { 1735*ecd6cf80Smarks nvlist_free(nvprops); 1736e9dbad6fSeschrock return (EINVAL); 1737e9dbad6fSeschrock } 1738e9dbad6fSeschrock 1739*ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 1740e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1741e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 1742*ecd6cf80Smarks nvlist_free(nvprops); 1743e9dbad6fSeschrock return (EINVAL); 1744e9dbad6fSeschrock } 1745e9dbad6fSeschrock 1746e9dbad6fSeschrock if (error != 0) 1747e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 1748e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 1749e9dbad6fSeschrock 1750e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 1751e9dbad6fSeschrock volblocksize)) != 0 || 1752e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 1753e9dbad6fSeschrock volblocksize)) != 0) { 1754*ecd6cf80Smarks nvlist_free(nvprops); 17555c5460e9Seschrock return (error); 1756e9dbad6fSeschrock } 1757fa9e4066Sahrens } 1758e9dbad6fSeschrock 1759e9dbad6fSeschrock error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, 1760*ecd6cf80Smarks nvprops); 1761fa9e4066Sahrens } 1762e9dbad6fSeschrock 1763e9dbad6fSeschrock /* 1764e9dbad6fSeschrock * It would be nice to do this atomically. 1765e9dbad6fSeschrock */ 1766e9dbad6fSeschrock if (error == 0) { 1767e9dbad6fSeschrock if ((error = zfs_set_prop_nvlist(zc->zc_name, 1768e9dbad6fSeschrock zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred, 1769*ecd6cf80Smarks nvprops)) != 0) 1770e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 1771e9dbad6fSeschrock } 1772e9dbad6fSeschrock 1773*ecd6cf80Smarks nvlist_free(nvprops); 1774fa9e4066Sahrens return (error); 1775fa9e4066Sahrens } 1776fa9e4066Sahrens 1777fa9e4066Sahrens static int 17781d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 1779fa9e4066Sahrens { 1780e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 17811d452cf5Sahrens return (EINVAL); 17821d452cf5Sahrens return (dmu_objset_snapshot(zc->zc_name, 1783e9dbad6fSeschrock zc->zc_value, zc->zc_cookie)); 17841d452cf5Sahrens } 1785fa9e4066Sahrens 1786cdf5b4caSmmusante int 17871d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 17881d452cf5Sahrens { 17891d452cf5Sahrens char *snapname = arg; 17901d452cf5Sahrens char *cp; 17910b69c2f0Sahrens vfs_t *vfsp = NULL; 17921d452cf5Sahrens 17931d452cf5Sahrens /* 17941d452cf5Sahrens * Snapshots (which are under .zfs control) must be unmounted 17951d452cf5Sahrens * before they can be destroyed. 17961d452cf5Sahrens */ 17971d452cf5Sahrens 17981d452cf5Sahrens if (snapname) { 17991d452cf5Sahrens (void) strcat(name, "@"); 18001d452cf5Sahrens (void) strcat(name, snapname); 18011d452cf5Sahrens vfsp = zfs_get_vfs(name); 18021d452cf5Sahrens cp = strchr(name, '@'); 18031d452cf5Sahrens *cp = '\0'; 18040b69c2f0Sahrens } else if (strchr(name, '@')) { 18051d452cf5Sahrens vfsp = zfs_get_vfs(name); 18061d452cf5Sahrens } 18071d452cf5Sahrens 18081d452cf5Sahrens if (vfsp) { 1809fa9e4066Sahrens /* 18101d452cf5Sahrens * Always force the unmount for snapshots. 1811fa9e4066Sahrens */ 18121d452cf5Sahrens int flag = MS_FORCE; 18131d452cf5Sahrens int err; 18141d452cf5Sahrens 18151d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 1816fa9e4066Sahrens VFS_RELE(vfsp); 18171d452cf5Sahrens return (err); 1818fa9e4066Sahrens } 18191d452cf5Sahrens VFS_RELE(vfsp); 18201d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 18211d452cf5Sahrens return (err); 18221d452cf5Sahrens } 18231d452cf5Sahrens return (0); 18241d452cf5Sahrens } 18251d452cf5Sahrens 18261d452cf5Sahrens static int 18271d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 18281d452cf5Sahrens { 18291d452cf5Sahrens int err; 18301d452cf5Sahrens 1831e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 18321d452cf5Sahrens return (EINVAL); 18331d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 1834e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 18351d452cf5Sahrens if (err) 18361d452cf5Sahrens return (err); 1837e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 18381d452cf5Sahrens } 18391d452cf5Sahrens 18401d452cf5Sahrens static int 18411d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 18421d452cf5Sahrens { 18431d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 18441d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 18451d452cf5Sahrens if (err) 18461d452cf5Sahrens return (err); 1847fa9e4066Sahrens } 1848fa9e4066Sahrens 1849fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 1850fa9e4066Sahrens } 1851fa9e4066Sahrens 1852fa9e4066Sahrens static int 1853fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 1854fa9e4066Sahrens { 1855fa9e4066Sahrens return (dmu_objset_rollback(zc->zc_name)); 1856fa9e4066Sahrens } 1857fa9e4066Sahrens 1858fa9e4066Sahrens static int 1859fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 1860fa9e4066Sahrens { 18617f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 1862cdf5b4caSmmusante 1863e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1864e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) 1865fa9e4066Sahrens return (EINVAL); 1866fa9e4066Sahrens 1867cdf5b4caSmmusante /* 1868cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 1869cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 1870cdf5b4caSmmusante * to unmount. 1871cdf5b4caSmmusante */ 1872cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 1873fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 18741d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 18751d452cf5Sahrens if (err) 18761d452cf5Sahrens return (err); 1877fa9e4066Sahrens } 1878fa9e4066Sahrens 1879cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 1880fa9e4066Sahrens } 1881fa9e4066Sahrens 1882fa9e4066Sahrens static int 1883fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc) 1884fa9e4066Sahrens { 1885fa9e4066Sahrens file_t *fp; 1886fa9e4066Sahrens int error, fd; 1887a2eea2e1Sahrens offset_t new_off; 1888fa9e4066Sahrens 18893ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 18903ccfa83cSahrens strchr(zc->zc_value, '@') == NULL) 18913ccfa83cSahrens return (EINVAL); 18923ccfa83cSahrens 1893fa9e4066Sahrens fd = zc->zc_cookie; 1894fa9e4066Sahrens fp = getf(fd); 1895fa9e4066Sahrens if (fp == NULL) 1896fa9e4066Sahrens return (EBADF); 1897e9dbad6fSeschrock error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record, 1898e9dbad6fSeschrock &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode, 189998579b20Snd fp->f_offset); 1900a2eea2e1Sahrens 1901a2eea2e1Sahrens new_off = fp->f_offset + zc->zc_cookie; 1902a2eea2e1Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0) 1903a2eea2e1Sahrens fp->f_offset = new_off; 1904a2eea2e1Sahrens 1905fa9e4066Sahrens releasef(fd); 1906fa9e4066Sahrens return (error); 1907fa9e4066Sahrens } 1908fa9e4066Sahrens 1909fa9e4066Sahrens static int 1910fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc) 1911fa9e4066Sahrens { 1912fa9e4066Sahrens objset_t *fromsnap = NULL; 1913fa9e4066Sahrens objset_t *tosnap; 1914fa9e4066Sahrens file_t *fp; 1915fa9e4066Sahrens int error; 1916fa9e4066Sahrens 1917fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1918fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); 1919fa9e4066Sahrens if (error) 1920fa9e4066Sahrens return (error); 1921fa9e4066Sahrens 1922e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1923a2eea2e1Sahrens char buf[MAXPATHLEN]; 1924a2eea2e1Sahrens char *cp; 1925a2eea2e1Sahrens 1926a2eea2e1Sahrens (void) strncpy(buf, zc->zc_name, sizeof (buf)); 1927a2eea2e1Sahrens cp = strchr(buf, '@'); 1928a2eea2e1Sahrens if (cp) 1929a2eea2e1Sahrens *(cp+1) = 0; 1930a2eea2e1Sahrens (void) strncat(buf, zc->zc_value, sizeof (buf)); 1931a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 1932fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); 1933fa9e4066Sahrens if (error) { 1934fa9e4066Sahrens dmu_objset_close(tosnap); 1935fa9e4066Sahrens return (error); 1936fa9e4066Sahrens } 1937fa9e4066Sahrens } 1938fa9e4066Sahrens 1939fa9e4066Sahrens fp = getf(zc->zc_cookie); 1940fa9e4066Sahrens if (fp == NULL) { 1941fa9e4066Sahrens dmu_objset_close(tosnap); 1942fa9e4066Sahrens if (fromsnap) 1943fa9e4066Sahrens dmu_objset_close(fromsnap); 1944fa9e4066Sahrens return (EBADF); 1945fa9e4066Sahrens } 1946fa9e4066Sahrens 1947fa9e4066Sahrens error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode); 1948fa9e4066Sahrens 1949fa9e4066Sahrens releasef(zc->zc_cookie); 1950fa9e4066Sahrens if (fromsnap) 1951fa9e4066Sahrens dmu_objset_close(fromsnap); 1952fa9e4066Sahrens dmu_objset_close(tosnap); 1953fa9e4066Sahrens return (error); 1954fa9e4066Sahrens } 1955fa9e4066Sahrens 1956ea8dc4b6Seschrock static int 1957ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 1958ea8dc4b6Seschrock { 1959ea8dc4b6Seschrock int id, error; 1960ea8dc4b6Seschrock 1961ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 1962ea8dc4b6Seschrock &zc->zc_inject_record); 1963ea8dc4b6Seschrock 1964ea8dc4b6Seschrock if (error == 0) 1965ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 1966ea8dc4b6Seschrock 1967ea8dc4b6Seschrock return (error); 1968ea8dc4b6Seschrock } 1969ea8dc4b6Seschrock 1970ea8dc4b6Seschrock static int 1971ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 1972ea8dc4b6Seschrock { 1973ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 1974ea8dc4b6Seschrock } 1975ea8dc4b6Seschrock 1976ea8dc4b6Seschrock static int 1977ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 1978ea8dc4b6Seschrock { 1979ea8dc4b6Seschrock int id = (int)zc->zc_guid; 1980ea8dc4b6Seschrock int error; 1981ea8dc4b6Seschrock 1982ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 1983ea8dc4b6Seschrock &zc->zc_inject_record); 1984ea8dc4b6Seschrock 1985ea8dc4b6Seschrock zc->zc_guid = id; 1986ea8dc4b6Seschrock 1987ea8dc4b6Seschrock return (error); 1988ea8dc4b6Seschrock } 1989ea8dc4b6Seschrock 1990ea8dc4b6Seschrock static int 1991ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 1992ea8dc4b6Seschrock { 1993ea8dc4b6Seschrock spa_t *spa; 1994ea8dc4b6Seschrock int error; 1995e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 1996ea8dc4b6Seschrock 1997ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1998ea8dc4b6Seschrock return (error); 1999ea8dc4b6Seschrock 2000e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2001ea8dc4b6Seschrock &count); 2002ea8dc4b6Seschrock if (error == 0) 2003e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2004ea8dc4b6Seschrock else 2005e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2006ea8dc4b6Seschrock 2007ea8dc4b6Seschrock spa_close(spa, FTAG); 2008ea8dc4b6Seschrock 2009ea8dc4b6Seschrock return (error); 2010ea8dc4b6Seschrock } 2011ea8dc4b6Seschrock 2012ea8dc4b6Seschrock static int 2013ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2014ea8dc4b6Seschrock { 2015ea8dc4b6Seschrock spa_t *spa; 2016ea8dc4b6Seschrock vdev_t *vd; 2017ea8dc4b6Seschrock int error; 20183d7072f8Seschrock uint64_t txg; 2019ea8dc4b6Seschrock 2020ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2021ea8dc4b6Seschrock return (error); 2022ea8dc4b6Seschrock 20233d7072f8Seschrock txg = spa_vdev_enter(spa); 2024ea8dc4b6Seschrock 2025e9dbad6fSeschrock if (zc->zc_guid == 0) { 2026ea8dc4b6Seschrock vd = NULL; 2027e9dbad6fSeschrock } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { 20283d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, ENODEV); 2029ea8dc4b6Seschrock spa_close(spa, FTAG); 2030ea8dc4b6Seschrock return (ENODEV); 2031ea8dc4b6Seschrock } 2032ea8dc4b6Seschrock 2033ea8dc4b6Seschrock vdev_clear(spa, vd); 2034ea8dc4b6Seschrock 20353d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, 0); 2036ea8dc4b6Seschrock 2037ea8dc4b6Seschrock spa_close(spa, FTAG); 2038ea8dc4b6Seschrock 2039ea8dc4b6Seschrock return (0); 2040ea8dc4b6Seschrock } 2041ea8dc4b6Seschrock 204299653d4eSeschrock static int 204399653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 204499653d4eSeschrock { 20450b69c2f0Sahrens char *cp; 20460b69c2f0Sahrens 20470b69c2f0Sahrens /* 20480b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 20490b69c2f0Sahrens * it's easier. 20500b69c2f0Sahrens */ 2051e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 20520b69c2f0Sahrens if (cp) 20530b69c2f0Sahrens *cp = '\0'; 2054e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 20550b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 205699653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 205799653d4eSeschrock } 205899653d4eSeschrock 2059*ecd6cf80Smarks /* 2060*ecd6cf80Smarks * We don't want to have a hard dependency 2061*ecd6cf80Smarks * against some special symbols in sharefs 2062*ecd6cf80Smarks * and nfs. Determine them if needed when 2063*ecd6cf80Smarks * the first file system is shared. 2064*ecd6cf80Smarks * Neither sharefs or nfs are unloadable modules. 2065*ecd6cf80Smarks */ 2066*ecd6cf80Smarks int (*zexport_fs)(void *arg); 2067*ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2068*ecd6cf80Smarks 2069*ecd6cf80Smarks int zfs_share_inited; 2070*ecd6cf80Smarks ddi_modhandle_t nfs_mod; 2071*ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 2072*ecd6cf80Smarks kmutex_t zfs_share_lock; 2073*ecd6cf80Smarks 2074*ecd6cf80Smarks static int 2075*ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 2076*ecd6cf80Smarks { 2077*ecd6cf80Smarks int error; 2078*ecd6cf80Smarks int opcode; 2079*ecd6cf80Smarks 2080*ecd6cf80Smarks if (zfs_share_inited == 0) { 2081*ecd6cf80Smarks mutex_enter(&zfs_share_lock); 2082*ecd6cf80Smarks nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error); 2083*ecd6cf80Smarks sharefs_mod = ddi_modopen("fs/sharefs", 2084*ecd6cf80Smarks KRTLD_MODE_FIRST, &error); 2085*ecd6cf80Smarks if (nfs_mod == NULL || sharefs_mod == NULL) { 2086*ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2087*ecd6cf80Smarks return (ENOSYS); 2088*ecd6cf80Smarks } 2089*ecd6cf80Smarks if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *)) 2090*ecd6cf80Smarks ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) { 2091*ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2092*ecd6cf80Smarks return (ENOSYS); 2093*ecd6cf80Smarks } 2094*ecd6cf80Smarks 2095*ecd6cf80Smarks if (zshare_fs == NULL && ((zshare_fs = 2096*ecd6cf80Smarks (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2097*ecd6cf80Smarks ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2098*ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2099*ecd6cf80Smarks return (ENOSYS); 2100*ecd6cf80Smarks } 2101*ecd6cf80Smarks zfs_share_inited = 1; 2102*ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2103*ecd6cf80Smarks } 2104*ecd6cf80Smarks 2105*ecd6cf80Smarks if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata)) 2106*ecd6cf80Smarks return (error); 2107*ecd6cf80Smarks 2108*ecd6cf80Smarks opcode = (zc->zc_share.z_sharetype == B_TRUE) ? 2109*ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 2110*ecd6cf80Smarks 2111*ecd6cf80Smarks error = zshare_fs(opcode, 2112*ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 2113*ecd6cf80Smarks zc->zc_share.z_sharemax); 2114*ecd6cf80Smarks 2115*ecd6cf80Smarks return (error); 2116*ecd6cf80Smarks 2117*ecd6cf80Smarks } 2118*ecd6cf80Smarks 2119*ecd6cf80Smarks /* 2120*ecd6cf80Smarks * pool destroy and pool export don't log the history as part of zfsdev_ioctl, 2121*ecd6cf80Smarks * but rather zfs_ioc_pool_create, and zfs_ioc_pool_export do the loggin 2122*ecd6cf80Smarks * of those commands. 2123*ecd6cf80Smarks */ 2124fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 2125*ecd6cf80Smarks { zfs_ioc_pool_create, zfs_secpolicy_config, pool_name, B_TRUE }, 2126*ecd6cf80Smarks { zfs_ioc_pool_destroy, zfs_secpolicy_config, pool_name, B_FALSE }, 2127*ecd6cf80Smarks { zfs_ioc_pool_import, zfs_secpolicy_config, pool_name, B_TRUE }, 2128*ecd6cf80Smarks { zfs_ioc_pool_export, zfs_secpolicy_config, pool_name, B_FALSE }, 2129*ecd6cf80Smarks { zfs_ioc_pool_configs, zfs_secpolicy_none, no_name, B_FALSE }, 2130*ecd6cf80Smarks { zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name, B_FALSE }, 2131*ecd6cf80Smarks { zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name, B_FALSE }, 2132*ecd6cf80Smarks { zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name, B_TRUE }, 2133*ecd6cf80Smarks { zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name, B_FALSE }, 2134*ecd6cf80Smarks { zfs_ioc_pool_upgrade, zfs_secpolicy_config, pool_name, B_TRUE }, 2135*ecd6cf80Smarks { zfs_ioc_pool_get_history, zfs_secpolicy_config, pool_name, B_FALSE }, 2136*ecd6cf80Smarks { zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name, B_TRUE }, 2137*ecd6cf80Smarks { zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name, B_TRUE }, 2138*ecd6cf80Smarks { zfs_ioc_vdev_set_state, zfs_secpolicy_config, pool_name, B_TRUE }, 2139*ecd6cf80Smarks { zfs_ioc_vdev_attach, zfs_secpolicy_config, pool_name, B_TRUE }, 2140*ecd6cf80Smarks { zfs_ioc_vdev_detach, zfs_secpolicy_config, pool_name, B_TRUE }, 2141*ecd6cf80Smarks { zfs_ioc_vdev_setpath, zfs_secpolicy_config, pool_name, B_FALSE }, 2142*ecd6cf80Smarks { zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name, B_FALSE }, 2143*ecd6cf80Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 2144*ecd6cf80Smarks dataset_name, B_FALSE }, 2145*ecd6cf80Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 2146*ecd6cf80Smarks dataset_name, B_FALSE }, 2147*ecd6cf80Smarks { zfs_ioc_set_prop, zfs_secpolicy_none, dataset_name, B_TRUE }, 2148*ecd6cf80Smarks { zfs_ioc_create_minor, zfs_secpolicy_minor, dataset_name, B_FALSE }, 2149*ecd6cf80Smarks { zfs_ioc_remove_minor, zfs_secpolicy_minor, dataset_name, B_FALSE }, 2150*ecd6cf80Smarks { zfs_ioc_create, zfs_secpolicy_create, dataset_name, B_TRUE }, 2151*ecd6cf80Smarks { zfs_ioc_destroy, zfs_secpolicy_destroy, dataset_name, B_TRUE }, 2152*ecd6cf80Smarks { zfs_ioc_rollback, zfs_secpolicy_rollback, dataset_name, B_TRUE }, 2153*ecd6cf80Smarks { zfs_ioc_rename, zfs_secpolicy_rename, dataset_name, B_TRUE }, 2154*ecd6cf80Smarks { zfs_ioc_recvbackup, zfs_secpolicy_receive, dataset_name, B_TRUE }, 2155*ecd6cf80Smarks { zfs_ioc_sendbackup, zfs_secpolicy_send, dataset_name, B_TRUE }, 2156*ecd6cf80Smarks { zfs_ioc_inject_fault, zfs_secpolicy_inject, no_name, B_FALSE }, 2157*ecd6cf80Smarks { zfs_ioc_clear_fault, zfs_secpolicy_inject, no_name, B_FALSE }, 2158*ecd6cf80Smarks { zfs_ioc_inject_list_next, zfs_secpolicy_inject, no_name, B_FALSE }, 2159*ecd6cf80Smarks { zfs_ioc_error_log, zfs_secpolicy_inject, pool_name, B_FALSE }, 2160*ecd6cf80Smarks { zfs_ioc_clear, zfs_secpolicy_config, pool_name, B_TRUE }, 2161*ecd6cf80Smarks { zfs_ioc_promote, zfs_secpolicy_promote, dataset_name, B_TRUE }, 2162*ecd6cf80Smarks { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, dataset_name, B_TRUE }, 2163*ecd6cf80Smarks { zfs_ioc_snapshot, zfs_secpolicy_snapshot, dataset_name, B_TRUE }, 2164*ecd6cf80Smarks { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, pool_name, B_FALSE }, 2165*ecd6cf80Smarks { zfs_ioc_obj_to_path, zfs_secpolicy_config, no_name, B_FALSE }, 2166*ecd6cf80Smarks { zfs_ioc_pool_set_props, zfs_secpolicy_config, pool_name, B_TRUE }, 2167*ecd6cf80Smarks { zfs_ioc_pool_get_props, zfs_secpolicy_read, pool_name, B_FALSE }, 2168*ecd6cf80Smarks { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, dataset_name, B_TRUE }, 2169*ecd6cf80Smarks { zfs_ioc_get_fsacl, zfs_secpolicy_read, dataset_name, B_FALSE }, 2170*ecd6cf80Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 2171*ecd6cf80Smarks dataset_name, B_FALSE }, 2172*ecd6cf80Smarks { zfs_ioc_share, zfs_secpolicy_share, dataset_name, B_FALSE } 2173fa9e4066Sahrens }; 2174fa9e4066Sahrens 2175fa9e4066Sahrens static int 2176fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2177fa9e4066Sahrens { 2178fa9e4066Sahrens zfs_cmd_t *zc; 2179fa9e4066Sahrens uint_t vec; 21801d452cf5Sahrens int error, rc; 2181fa9e4066Sahrens 2182fa9e4066Sahrens if (getminor(dev) != 0) 2183fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2184fa9e4066Sahrens 2185fa9e4066Sahrens vec = cmd - ZFS_IOC; 2186fa9e4066Sahrens 2187fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2188fa9e4066Sahrens return (EINVAL); 2189fa9e4066Sahrens 2190fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2191fa9e4066Sahrens 2192fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2193fa9e4066Sahrens 2194fa9e4066Sahrens if (error == 0) { 2195fa9e4066Sahrens zc->zc_cred = (uintptr_t)cr; 2196fa9e4066Sahrens zc->zc_dev = dev; 2197*ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2198fa9e4066Sahrens } 2199fa9e4066Sahrens 2200fa9e4066Sahrens /* 2201fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2202fa9e4066Sahrens * the lower layers. 2203fa9e4066Sahrens */ 2204fa9e4066Sahrens if (error == 0) { 2205fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2206fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 2207fa9e4066Sahrens case pool_name: 2208fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2209fa9e4066Sahrens error = EINVAL; 2210fa9e4066Sahrens break; 2211fa9e4066Sahrens 2212fa9e4066Sahrens case dataset_name: 2213fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2214fa9e4066Sahrens error = EINVAL; 2215fa9e4066Sahrens break; 22165ad82045Snd 22175ad82045Snd case no_name: 22185ad82045Snd break; 2219fa9e4066Sahrens } 2220fa9e4066Sahrens } 2221fa9e4066Sahrens 2222fa9e4066Sahrens if (error == 0) 2223fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2224fa9e4066Sahrens 22251d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 2226*ecd6cf80Smarks if (error == 0) { 22271d452cf5Sahrens error = rc; 2228*ecd6cf80Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 2229*ecd6cf80Smarks zfs_log_history(zc); 2230*ecd6cf80Smarks } 2231fa9e4066Sahrens 2232fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 2233fa9e4066Sahrens return (error); 2234fa9e4066Sahrens } 2235fa9e4066Sahrens 2236fa9e4066Sahrens static int 2237fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2238fa9e4066Sahrens { 2239fa9e4066Sahrens if (cmd != DDI_ATTACH) 2240fa9e4066Sahrens return (DDI_FAILURE); 2241fa9e4066Sahrens 2242fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 2243fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 2244fa9e4066Sahrens return (DDI_FAILURE); 2245fa9e4066Sahrens 2246fa9e4066Sahrens zfs_dip = dip; 2247fa9e4066Sahrens 2248fa9e4066Sahrens ddi_report_dev(dip); 2249fa9e4066Sahrens 2250fa9e4066Sahrens return (DDI_SUCCESS); 2251fa9e4066Sahrens } 2252fa9e4066Sahrens 2253fa9e4066Sahrens static int 2254fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2255fa9e4066Sahrens { 2256fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 2257fa9e4066Sahrens return (DDI_FAILURE); 2258fa9e4066Sahrens 2259fa9e4066Sahrens if (cmd != DDI_DETACH) 2260fa9e4066Sahrens return (DDI_FAILURE); 2261fa9e4066Sahrens 2262fa9e4066Sahrens zfs_dip = NULL; 2263fa9e4066Sahrens 2264fa9e4066Sahrens ddi_prop_remove_all(dip); 2265fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 2266fa9e4066Sahrens 2267fa9e4066Sahrens return (DDI_SUCCESS); 2268fa9e4066Sahrens } 2269fa9e4066Sahrens 2270fa9e4066Sahrens /*ARGSUSED*/ 2271fa9e4066Sahrens static int 2272fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2273fa9e4066Sahrens { 2274fa9e4066Sahrens switch (infocmd) { 2275fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 2276fa9e4066Sahrens *result = zfs_dip; 2277fa9e4066Sahrens return (DDI_SUCCESS); 2278fa9e4066Sahrens 2279fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 2280a0965f35Sbonwick *result = (void *)0; 2281fa9e4066Sahrens return (DDI_SUCCESS); 2282fa9e4066Sahrens } 2283fa9e4066Sahrens 2284fa9e4066Sahrens return (DDI_FAILURE); 2285fa9e4066Sahrens } 2286fa9e4066Sahrens 2287fa9e4066Sahrens /* 2288fa9e4066Sahrens * OK, so this is a little weird. 2289fa9e4066Sahrens * 2290fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 2291fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 2292fa9e4066Sahrens * 2293fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 2294fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 2295fa9e4066Sahrens */ 2296fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 2297fa9e4066Sahrens zvol_open, /* open */ 2298fa9e4066Sahrens zvol_close, /* close */ 2299fa9e4066Sahrens zvol_strategy, /* strategy */ 2300fa9e4066Sahrens nodev, /* print */ 2301fa9e4066Sahrens nodev, /* dump */ 2302fa9e4066Sahrens zvol_read, /* read */ 2303fa9e4066Sahrens zvol_write, /* write */ 2304fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 2305fa9e4066Sahrens nodev, /* devmap */ 2306fa9e4066Sahrens nodev, /* mmap */ 2307fa9e4066Sahrens nodev, /* segmap */ 2308fa9e4066Sahrens nochpoll, /* poll */ 2309fa9e4066Sahrens ddi_prop_op, /* prop_op */ 2310fa9e4066Sahrens NULL, /* streamtab */ 2311fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 2312fa9e4066Sahrens CB_REV, /* version */ 2313feb08c6bSbillm nodev, /* async read */ 2314feb08c6bSbillm nodev, /* async write */ 2315fa9e4066Sahrens }; 2316fa9e4066Sahrens 2317fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 2318fa9e4066Sahrens DEVO_REV, /* version */ 2319fa9e4066Sahrens 0, /* refcnt */ 2320fa9e4066Sahrens zfs_info, /* info */ 2321fa9e4066Sahrens nulldev, /* identify */ 2322fa9e4066Sahrens nulldev, /* probe */ 2323fa9e4066Sahrens zfs_attach, /* attach */ 2324fa9e4066Sahrens zfs_detach, /* detach */ 2325fa9e4066Sahrens nodev, /* reset */ 2326fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 2327fa9e4066Sahrens NULL /* no bus operations */ 2328fa9e4066Sahrens }; 2329fa9e4066Sahrens 2330fa9e4066Sahrens static struct modldrv zfs_modldrv = { 2331e9dbad6fSeschrock &mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING, 2332e9dbad6fSeschrock &zfs_dev_ops 2333fa9e4066Sahrens }; 2334fa9e4066Sahrens 2335fa9e4066Sahrens static struct modlinkage modlinkage = { 2336fa9e4066Sahrens MODREV_1, 2337fa9e4066Sahrens (void *)&zfs_modlfs, 2338fa9e4066Sahrens (void *)&zfs_modldrv, 2339fa9e4066Sahrens NULL 2340fa9e4066Sahrens }; 2341fa9e4066Sahrens 2342fa9e4066Sahrens int 2343fa9e4066Sahrens _init(void) 2344fa9e4066Sahrens { 2345fa9e4066Sahrens int error; 2346fa9e4066Sahrens 2347a0965f35Sbonwick spa_init(FREAD | FWRITE); 2348a0965f35Sbonwick zfs_init(); 2349a0965f35Sbonwick zvol_init(); 2350a0965f35Sbonwick 2351a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 2352a0965f35Sbonwick zvol_fini(); 2353a0965f35Sbonwick zfs_fini(); 2354a0965f35Sbonwick spa_fini(); 2355fa9e4066Sahrens return (error); 2356a0965f35Sbonwick } 2357fa9e4066Sahrens 2358fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 2359fa9e4066Sahrens ASSERT(error == 0); 2360*ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 2361fa9e4066Sahrens 2362fa9e4066Sahrens return (0); 2363fa9e4066Sahrens } 2364fa9e4066Sahrens 2365fa9e4066Sahrens int 2366fa9e4066Sahrens _fini(void) 2367fa9e4066Sahrens { 2368fa9e4066Sahrens int error; 2369fa9e4066Sahrens 2370ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 2371fa9e4066Sahrens return (EBUSY); 2372fa9e4066Sahrens 2373fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 2374fa9e4066Sahrens return (error); 2375fa9e4066Sahrens 2376fa9e4066Sahrens zvol_fini(); 2377fa9e4066Sahrens zfs_fini(); 2378fa9e4066Sahrens spa_fini(); 2379*ecd6cf80Smarks if (zfs_share_inited) { 2380*ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 2381*ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 2382*ecd6cf80Smarks } 2383fa9e4066Sahrens 2384fa9e4066Sahrens ldi_ident_release(zfs_li); 2385fa9e4066Sahrens zfs_li = NULL; 2386*ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 2387fa9e4066Sahrens 2388fa9e4066Sahrens return (error); 2389fa9e4066Sahrens } 2390fa9e4066Sahrens 2391fa9e4066Sahrens int 2392fa9e4066Sahrens _info(struct modinfo *modinfop) 2393fa9e4066Sahrens { 2394fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 2395fa9e4066Sahrens } 2396