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> 50ecd6cf80Smarks #include <sys/dsl_deleg.h> 51ecd6cf80Smarks #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> 64ecd6cf80Smarks #include <sharefs/share.h> 65e7437265Sahrens #include <sys/zfs_znode.h> 66fa9e4066Sahrens 67fa9e4066Sahrens #include "zfs_namecheck.h" 68e9dbad6fSeschrock #include "zfs_prop.h" 69ecd6cf80Smarks #include "zfs_deleg.h" 70fa9e4066Sahrens 71fa9e4066Sahrens extern struct modlfs zfs_modlfs; 72fa9e4066Sahrens 73fa9e4066Sahrens extern void zfs_init(void); 74fa9e4066Sahrens extern void zfs_fini(void); 75fa9e4066Sahrens 76fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 77fa9e4066Sahrens dev_info_t *zfs_dip; 78fa9e4066Sahrens 79fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 80ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 81fa9e4066Sahrens 82fa9e4066Sahrens typedef struct zfs_ioc_vec { 83fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 84fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 85fa9e4066Sahrens enum { 86e7437265Sahrens NO_NAME, 87e7437265Sahrens POOL_NAME, 88e7437265Sahrens DATASET_NAME 89ecd6cf80Smarks } zvec_namecheck; 90ecd6cf80Smarks boolean_t zvec_his_log; 91fa9e4066Sahrens } zfs_ioc_vec_t; 92fa9e4066Sahrens 93fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 94fa9e4066Sahrens void 95fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 96fa9e4066Sahrens { 97fa9e4066Sahrens const char *newfile; 98fa9e4066Sahrens char buf[256]; 99fa9e4066Sahrens va_list adx; 100fa9e4066Sahrens 101fa9e4066Sahrens /* 102fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 103fa9e4066Sahrens */ 104fa9e4066Sahrens newfile = strrchr(file, '/'); 105fa9e4066Sahrens if (newfile != NULL) { 106fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 107fa9e4066Sahrens } else { 108fa9e4066Sahrens newfile = file; 109fa9e4066Sahrens } 110fa9e4066Sahrens 111fa9e4066Sahrens va_start(adx, fmt); 112fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 113fa9e4066Sahrens va_end(adx); 114fa9e4066Sahrens 115fa9e4066Sahrens /* 116fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 117fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 118fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 119fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 120fa9e4066Sahrens * arg0 = file name 121fa9e4066Sahrens * arg1 = function name 122fa9e4066Sahrens * arg2 = line number 123fa9e4066Sahrens * arg3 = message 124fa9e4066Sahrens */ 125fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 126fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 127fa9e4066Sahrens } 128fa9e4066Sahrens 129ecd6cf80Smarks static void 130ecd6cf80Smarks zfs_log_history(zfs_cmd_t *zc) 131ecd6cf80Smarks { 132ecd6cf80Smarks spa_t *spa; 133*40feaa91Sahrens char *buf; 134ecd6cf80Smarks 135ecd6cf80Smarks if (zc->zc_history == NULL) 136ecd6cf80Smarks return; 137ecd6cf80Smarks 138e7437265Sahrens if (zc->zc_history_offset != LOG_CMD_POOL_CREATE && 139e7437265Sahrens zc->zc_history_offset != LOG_CMD_NORMAL) 140e7437265Sahrens return; 141e7437265Sahrens 142ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 143ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 144ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 145ecd6cf80Smarks kmem_free(buf, HIS_MAX_RECORD_LEN); 146ecd6cf80Smarks return; 147ecd6cf80Smarks } 148ecd6cf80Smarks 149ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 150ecd6cf80Smarks 151*40feaa91Sahrens if (spa_open(zc->zc_name, &spa, FTAG) != 0) { 152ecd6cf80Smarks kmem_free(buf, HIS_MAX_RECORD_LEN); 153ecd6cf80Smarks return; 154ecd6cf80Smarks } 155ecd6cf80Smarks 156e7437265Sahrens if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 157ecd6cf80Smarks (void) spa_history_log(spa, buf, zc->zc_history_offset); 158ecd6cf80Smarks 159ecd6cf80Smarks spa_close(spa, FTAG); 160ecd6cf80Smarks kmem_free(buf, HIS_MAX_RECORD_LEN); 161ecd6cf80Smarks } 162ecd6cf80Smarks 163fa9e4066Sahrens /* 164fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 165fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 166fa9e4066Sahrens */ 167fa9e4066Sahrens /* ARGSUSED */ 168fa9e4066Sahrens static int 169ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 170fa9e4066Sahrens { 171fa9e4066Sahrens return (0); 172fa9e4066Sahrens } 173fa9e4066Sahrens 174fa9e4066Sahrens /* 175fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 176fa9e4066Sahrens * no privileges, but must be visible in the local zone. 177fa9e4066Sahrens */ 178fa9e4066Sahrens /* ARGSUSED */ 179fa9e4066Sahrens static int 180ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 181fa9e4066Sahrens { 182fa9e4066Sahrens if (INGLOBALZONE(curproc) || 183ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 184fa9e4066Sahrens return (0); 185fa9e4066Sahrens 186fa9e4066Sahrens return (ENOENT); 187fa9e4066Sahrens } 188fa9e4066Sahrens 189fa9e4066Sahrens static int 190fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 191fa9e4066Sahrens { 192fa9e4066Sahrens uint64_t zoned; 193fa9e4066Sahrens int writable = 1; 194fa9e4066Sahrens 195fa9e4066Sahrens /* 196fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 197fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 198fa9e4066Sahrens */ 199fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 200fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 201fa9e4066Sahrens return (ENOENT); 202fa9e4066Sahrens 203fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 204fa9e4066Sahrens return (ENOENT); 205fa9e4066Sahrens 206fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 207fa9e4066Sahrens /* 208fa9e4066Sahrens * If the fs is zoned, only root can access it from the 209fa9e4066Sahrens * global zone. 210fa9e4066Sahrens */ 211fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 212fa9e4066Sahrens return (EPERM); 213fa9e4066Sahrens } else { 214fa9e4066Sahrens /* 215fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 216fa9e4066Sahrens */ 217fa9e4066Sahrens if (!zoned) 218fa9e4066Sahrens return (EPERM); 219fa9e4066Sahrens 220fa9e4066Sahrens /* must be writable by this zone */ 221fa9e4066Sahrens if (!writable) 222fa9e4066Sahrens return (EPERM); 223fa9e4066Sahrens } 224fa9e4066Sahrens return (0); 225fa9e4066Sahrens } 226fa9e4066Sahrens 227fa9e4066Sahrens int 228ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 229fa9e4066Sahrens { 230fa9e4066Sahrens int error; 231fa9e4066Sahrens 232ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 233ecd6cf80Smarks if (error == 0) { 234ecd6cf80Smarks error = secpolicy_zfs(cr); 235ecd6cf80Smarks if (error) { 236ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 237ecd6cf80Smarks } 238ecd6cf80Smarks } 239ecd6cf80Smarks return (error); 240ecd6cf80Smarks } 241ecd6cf80Smarks 242ecd6cf80Smarks static int 243ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 244ecd6cf80Smarks { 245ecd6cf80Smarks int error = 0; 246ecd6cf80Smarks 247ecd6cf80Smarks /* 248ecd6cf80Smarks * Check permissions for special properties. 249ecd6cf80Smarks */ 250ecd6cf80Smarks switch (prop) { 251ecd6cf80Smarks case ZFS_PROP_ZONED: 252ecd6cf80Smarks /* 253ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 254ecd6cf80Smarks */ 255ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 256ecd6cf80Smarks return (EPERM); 257ecd6cf80Smarks break; 258ecd6cf80Smarks 259ecd6cf80Smarks case ZFS_PROP_QUOTA: 260ecd6cf80Smarks if (error = 261ecd6cf80Smarks zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_QUOTA, cr)) 262ecd6cf80Smarks return (error); 263ecd6cf80Smarks 264ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 265ecd6cf80Smarks uint64_t zoned; 266ecd6cf80Smarks char setpoint[MAXNAMELEN]; 267ecd6cf80Smarks int dslen; 268ecd6cf80Smarks /* 269ecd6cf80Smarks * Unprivileged users are allowed to modify the 270ecd6cf80Smarks * quota on things *under* (ie. contained by) 271ecd6cf80Smarks * the thing they own. 272ecd6cf80Smarks */ 273ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 274ecd6cf80Smarks setpoint)) 275ecd6cf80Smarks return (EPERM); 276ecd6cf80Smarks if (!zoned) /* this shouldn't happen */ 277ecd6cf80Smarks return (EPERM); 278ecd6cf80Smarks dslen = strlen(name); 279ecd6cf80Smarks if (dslen <= strlen(setpoint)) 280ecd6cf80Smarks return (EPERM); 281ecd6cf80Smarks } 282ecd6cf80Smarks default: 283ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 284ecd6cf80Smarks zfs_prop_perm(prop), cr); 285ecd6cf80Smarks } 286ecd6cf80Smarks 287ecd6cf80Smarks return (error); 288ecd6cf80Smarks } 289ecd6cf80Smarks 290ecd6cf80Smarks int 291ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 292ecd6cf80Smarks { 293ecd6cf80Smarks int error; 294ecd6cf80Smarks 295ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 296ecd6cf80Smarks if (error) 297fa9e4066Sahrens return (error); 298fa9e4066Sahrens 299ecd6cf80Smarks /* 300ecd6cf80Smarks * permission to set permissions will be evaluated later in 301ecd6cf80Smarks * dsl_deleg_can_allow() 302ecd6cf80Smarks */ 303ecd6cf80Smarks return (0); 304ecd6cf80Smarks } 305ecd6cf80Smarks 306ecd6cf80Smarks int 307ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 308ecd6cf80Smarks { 309ecd6cf80Smarks int error; 310ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 311ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 312ecd6cf80Smarks if (error == 0) 313ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 314ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 315ecd6cf80Smarks return (error); 316ecd6cf80Smarks } 317ecd6cf80Smarks 318ecd6cf80Smarks int 319ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 320ecd6cf80Smarks { 321ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 322ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 323ecd6cf80Smarks } 324ecd6cf80Smarks 325ecd6cf80Smarks int 326ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 327ecd6cf80Smarks { 328ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 329ecd6cf80Smarks return (EPERM); 330ecd6cf80Smarks 331ecd6cf80Smarks if (secpolicy_nfs(CRED()) == 0) { 332ecd6cf80Smarks return (0); 333ecd6cf80Smarks } else { 334ecd6cf80Smarks vnode_t *vp; 335ecd6cf80Smarks int error; 336ecd6cf80Smarks 337ecd6cf80Smarks if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 338ecd6cf80Smarks NO_FOLLOW, NULL, &vp)) != 0) 339ecd6cf80Smarks return (error); 340ecd6cf80Smarks 341ecd6cf80Smarks /* Now make sure mntpnt and dataset are ZFS */ 342ecd6cf80Smarks 343ecd6cf80Smarks if (vp->v_vfsp->vfs_fstype != zfsfstype || 344ecd6cf80Smarks (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 345ecd6cf80Smarks zc->zc_name) != 0)) { 346ecd6cf80Smarks VN_RELE(vp); 347ecd6cf80Smarks return (EPERM); 348ecd6cf80Smarks } 349ecd6cf80Smarks 350ecd6cf80Smarks VN_RELE(vp); 351ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 352ecd6cf80Smarks ZFS_DELEG_PERM_SHARE, cr)); 353ecd6cf80Smarks } 354fa9e4066Sahrens } 355fa9e4066Sahrens 356fa9e4066Sahrens static int 357ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 358fa9e4066Sahrens { 359fa9e4066Sahrens char *cp; 360fa9e4066Sahrens 361fa9e4066Sahrens /* 362fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 363fa9e4066Sahrens */ 364ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 365ecd6cf80Smarks cp = strrchr(parent, '@'); 366fa9e4066Sahrens if (cp != NULL) { 367fa9e4066Sahrens cp[0] = '\0'; 368fa9e4066Sahrens } else { 369ecd6cf80Smarks cp = strrchr(parent, '/'); 370fa9e4066Sahrens if (cp == NULL) 371fa9e4066Sahrens return (ENOENT); 372fa9e4066Sahrens cp[0] = '\0'; 373ecd6cf80Smarks } 374ecd6cf80Smarks 375ecd6cf80Smarks return (0); 376ecd6cf80Smarks } 377ecd6cf80Smarks 378ecd6cf80Smarks int 379ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 380ecd6cf80Smarks { 381ecd6cf80Smarks int error; 382ecd6cf80Smarks 383ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 384ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 385ecd6cf80Smarks return (error); 386ecd6cf80Smarks 387ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 388ecd6cf80Smarks } 389ecd6cf80Smarks 390ecd6cf80Smarks static int 391ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 392ecd6cf80Smarks { 393ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 394ecd6cf80Smarks } 395ecd6cf80Smarks 396ecd6cf80Smarks /* 397ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 398ecd6cf80Smarks */ 399ecd6cf80Smarks /* ARGSUSED */ 400ecd6cf80Smarks static int 401ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 402ecd6cf80Smarks { 403ecd6cf80Smarks return (secpolicy_zfs(cr)); 404ecd6cf80Smarks } 405ecd6cf80Smarks 406ecd6cf80Smarks int 407ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 408ecd6cf80Smarks { 409ecd6cf80Smarks char parentname[MAXNAMELEN]; 410ecd6cf80Smarks int error; 411ecd6cf80Smarks 412ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 413ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 414ecd6cf80Smarks return (error); 415ecd6cf80Smarks 416ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 417ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 418ecd6cf80Smarks return (error); 419ecd6cf80Smarks 420ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 421ecd6cf80Smarks sizeof (parentname))) != 0) 422ecd6cf80Smarks return (error); 423ecd6cf80Smarks 424ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 425ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 426ecd6cf80Smarks return (error); 427ecd6cf80Smarks 428ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 429ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 430ecd6cf80Smarks return (error); 431ecd6cf80Smarks 432ecd6cf80Smarks return (error); 433ecd6cf80Smarks } 434ecd6cf80Smarks 435ecd6cf80Smarks static int 436ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 437ecd6cf80Smarks { 438ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 439ecd6cf80Smarks } 440ecd6cf80Smarks 441ecd6cf80Smarks static int 442ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 443ecd6cf80Smarks { 444ecd6cf80Smarks char parentname[MAXNAMELEN]; 445ecd6cf80Smarks objset_t *clone; 446ecd6cf80Smarks int error; 447ecd6cf80Smarks 448ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 449ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 450ecd6cf80Smarks if (error) 451ecd6cf80Smarks return (error); 452ecd6cf80Smarks 453ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 454ecd6cf80Smarks DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 455ecd6cf80Smarks 456ecd6cf80Smarks if (error == 0) { 457ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 458ecd6cf80Smarks dsl_dir_t *dd; 459ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 460ecd6cf80Smarks 461ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 462ecd6cf80Smarks error = dsl_dataset_open_obj(dd->dd_pool, 463ecd6cf80Smarks dd->dd_phys->dd_clone_parent_obj, NULL, 464ecd6cf80Smarks DS_MODE_NONE, FTAG, &pclone); 465ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 466ecd6cf80Smarks if (error) { 467ecd6cf80Smarks dmu_objset_close(clone); 468ecd6cf80Smarks return (error); 469ecd6cf80Smarks } 470ecd6cf80Smarks 471ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 472ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 473ecd6cf80Smarks 474ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 475ecd6cf80Smarks dmu_objset_close(clone); 476ecd6cf80Smarks dsl_dataset_close(pclone, DS_MODE_NONE, FTAG); 477ecd6cf80Smarks if (error == 0) 478ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 479ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 480ecd6cf80Smarks } 481ecd6cf80Smarks return (error); 482ecd6cf80Smarks } 483ecd6cf80Smarks 484ecd6cf80Smarks static int 485ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 486ecd6cf80Smarks { 487ecd6cf80Smarks int error; 488ecd6cf80Smarks 489ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 490ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 491ecd6cf80Smarks return (error); 492ecd6cf80Smarks 493ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 494ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 495ecd6cf80Smarks return (error); 496ecd6cf80Smarks 497ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 498ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 499ecd6cf80Smarks } 500ecd6cf80Smarks 501ecd6cf80Smarks int 502ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 503ecd6cf80Smarks { 504ecd6cf80Smarks int error; 505ecd6cf80Smarks 506ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 507ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 508ecd6cf80Smarks return (error); 509ecd6cf80Smarks 510ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 511ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 512ecd6cf80Smarks 513ecd6cf80Smarks return (error); 514ecd6cf80Smarks } 515ecd6cf80Smarks 516ecd6cf80Smarks static int 517ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 518ecd6cf80Smarks { 519ecd6cf80Smarks 520ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 521ecd6cf80Smarks } 522ecd6cf80Smarks 523ecd6cf80Smarks static int 524ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 525ecd6cf80Smarks { 526ecd6cf80Smarks char parentname[MAXNAMELEN]; 527ecd6cf80Smarks int error; 528ecd6cf80Smarks 529ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 530ecd6cf80Smarks sizeof (parentname))) != 0) 531ecd6cf80Smarks return (error); 532fa9e4066Sahrens 533ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 534ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 535ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 536ecd6cf80Smarks return (error); 537fa9e4066Sahrens } 538fa9e4066Sahrens 539ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 540ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 541ecd6cf80Smarks return (error); 542ecd6cf80Smarks 543ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 544ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 545ecd6cf80Smarks 546ecd6cf80Smarks return (error); 547ecd6cf80Smarks } 548ecd6cf80Smarks 549ecd6cf80Smarks static int 550ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 551ecd6cf80Smarks { 552ecd6cf80Smarks int error; 553ecd6cf80Smarks 554ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 555ecd6cf80Smarks if (error) { 556ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 557ecd6cf80Smarks } 558ecd6cf80Smarks return (error); 559fa9e4066Sahrens } 560fa9e4066Sahrens 561fa9e4066Sahrens /* 562fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 563fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 564fa9e4066Sahrens */ 565fa9e4066Sahrens /* ARGSUSED */ 566fa9e4066Sahrens static int 567ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 568fa9e4066Sahrens { 569fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 570fa9e4066Sahrens return (EPERM); 571fa9e4066Sahrens 572fa9e4066Sahrens return (0); 573fa9e4066Sahrens } 574fa9e4066Sahrens 575ecd6cf80Smarks /* 576ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 577ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 578ecd6cf80Smarks * the minor nodes. 579ecd6cf80Smarks */ 580ecd6cf80Smarks static int 581ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 582ecd6cf80Smarks { 583ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 584ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 585ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 586ecd6cf80Smarks } 587ecd6cf80Smarks 588ecd6cf80Smarks return (0); 589ecd6cf80Smarks } 590ecd6cf80Smarks 591ea8dc4b6Seschrock /* 592ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 593ea8dc4b6Seschrock */ 594ea8dc4b6Seschrock /* ARGSUSED */ 595ea8dc4b6Seschrock static int 596ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 597ea8dc4b6Seschrock { 598ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 599ea8dc4b6Seschrock } 600ea8dc4b6Seschrock 601fa9e4066Sahrens /* 602fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 603fa9e4066Sahrens */ 604fa9e4066Sahrens static int 605e9dbad6fSeschrock get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp) 606fa9e4066Sahrens { 607fa9e4066Sahrens char *packed; 608fa9e4066Sahrens size_t size; 609fa9e4066Sahrens int error; 610fa9e4066Sahrens nvlist_t *config = NULL; 611fa9e4066Sahrens 612fa9e4066Sahrens /* 613e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 614fa9e4066Sahrens */ 615e9dbad6fSeschrock if ((size = zc->zc_nvlist_src_size) == 0) 616fa9e4066Sahrens return (EINVAL); 617fa9e4066Sahrens 618fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 619fa9e4066Sahrens 620e9dbad6fSeschrock if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed, 621fa9e4066Sahrens size)) != 0) { 622fa9e4066Sahrens kmem_free(packed, size); 623fa9e4066Sahrens return (error); 624fa9e4066Sahrens } 625fa9e4066Sahrens 626fa9e4066Sahrens if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) { 627fa9e4066Sahrens kmem_free(packed, size); 628fa9e4066Sahrens return (error); 629fa9e4066Sahrens } 630fa9e4066Sahrens 631fa9e4066Sahrens kmem_free(packed, size); 632fa9e4066Sahrens 633fa9e4066Sahrens *nvp = config; 634fa9e4066Sahrens return (0); 635fa9e4066Sahrens } 636fa9e4066Sahrens 637e9dbad6fSeschrock static int 638e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 639e9dbad6fSeschrock { 640e9dbad6fSeschrock char *packed = NULL; 641e9dbad6fSeschrock size_t size; 642e9dbad6fSeschrock int error; 643e9dbad6fSeschrock 644e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 645e9dbad6fSeschrock 646e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 647e9dbad6fSeschrock error = ENOMEM; 648e9dbad6fSeschrock } else { 649e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 650e9dbad6fSeschrock KM_SLEEP) == 0); 651e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 652e9dbad6fSeschrock size); 653e9dbad6fSeschrock kmem_free(packed, size); 654e9dbad6fSeschrock } 655e9dbad6fSeschrock 656e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 657e9dbad6fSeschrock return (error); 658e9dbad6fSeschrock } 659e9dbad6fSeschrock 660fa9e4066Sahrens static int 661fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 662fa9e4066Sahrens { 663fa9e4066Sahrens int error; 664fa9e4066Sahrens nvlist_t *config; 665fa9e4066Sahrens 666e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) != 0) 667fa9e4066Sahrens return (error); 668fa9e4066Sahrens 669e9dbad6fSeschrock error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ? 670e9dbad6fSeschrock NULL : zc->zc_value); 671fa9e4066Sahrens 672fa9e4066Sahrens nvlist_free(config); 673fa9e4066Sahrens 674fa9e4066Sahrens return (error); 675fa9e4066Sahrens } 676fa9e4066Sahrens 677fa9e4066Sahrens static int 678fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 679fa9e4066Sahrens { 680ecd6cf80Smarks int error; 681ecd6cf80Smarks zfs_log_history(zc); 682ecd6cf80Smarks error = spa_destroy(zc->zc_name); 683ecd6cf80Smarks return (error); 684fa9e4066Sahrens } 685fa9e4066Sahrens 686fa9e4066Sahrens static int 687fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 688fa9e4066Sahrens { 689fa9e4066Sahrens int error; 690fa9e4066Sahrens nvlist_t *config; 691fa9e4066Sahrens uint64_t guid; 692fa9e4066Sahrens 693e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) != 0) 694fa9e4066Sahrens return (error); 695fa9e4066Sahrens 696fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 697ea8dc4b6Seschrock guid != zc->zc_guid) 698fa9e4066Sahrens error = EINVAL; 699fa9e4066Sahrens else 700fa9e4066Sahrens error = spa_import(zc->zc_name, config, 701e9dbad6fSeschrock zc->zc_value[0] == '\0' ? NULL : zc->zc_value); 702fa9e4066Sahrens 703fa9e4066Sahrens nvlist_free(config); 704fa9e4066Sahrens 705fa9e4066Sahrens return (error); 706fa9e4066Sahrens } 707fa9e4066Sahrens 708fa9e4066Sahrens static int 709fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 710fa9e4066Sahrens { 711ecd6cf80Smarks int error; 712ecd6cf80Smarks zfs_log_history(zc); 713ecd6cf80Smarks error = spa_export(zc->zc_name, NULL); 714ecd6cf80Smarks return (error); 715fa9e4066Sahrens } 716fa9e4066Sahrens 717fa9e4066Sahrens static int 718fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 719fa9e4066Sahrens { 720fa9e4066Sahrens nvlist_t *configs; 721fa9e4066Sahrens int error; 722fa9e4066Sahrens 723fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 724fa9e4066Sahrens return (EEXIST); 725fa9e4066Sahrens 726e9dbad6fSeschrock error = put_nvlist(zc, configs); 727fa9e4066Sahrens 728fa9e4066Sahrens nvlist_free(configs); 729fa9e4066Sahrens 730fa9e4066Sahrens return (error); 731fa9e4066Sahrens } 732fa9e4066Sahrens 733fa9e4066Sahrens static int 734fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 735fa9e4066Sahrens { 736fa9e4066Sahrens nvlist_t *config; 737fa9e4066Sahrens int error; 738ea8dc4b6Seschrock int ret = 0; 739fa9e4066Sahrens 740e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 741e9dbad6fSeschrock sizeof (zc->zc_value)); 742fa9e4066Sahrens 743fa9e4066Sahrens if (config != NULL) { 744e9dbad6fSeschrock ret = put_nvlist(zc, config); 745fa9e4066Sahrens nvlist_free(config); 746ea8dc4b6Seschrock 747ea8dc4b6Seschrock /* 748ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 749ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 750ea8dc4b6Seschrock * in 'zc_cookie'. 751ea8dc4b6Seschrock */ 752ea8dc4b6Seschrock zc->zc_cookie = error; 753fa9e4066Sahrens } else { 754ea8dc4b6Seschrock ret = error; 755fa9e4066Sahrens } 756fa9e4066Sahrens 757ea8dc4b6Seschrock return (ret); 758fa9e4066Sahrens } 759fa9e4066Sahrens 760fa9e4066Sahrens /* 761fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 762fa9e4066Sahrens * user land knows which devices are available and overall pool health. 763fa9e4066Sahrens */ 764fa9e4066Sahrens static int 765fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 766fa9e4066Sahrens { 767fa9e4066Sahrens nvlist_t *tryconfig, *config; 768fa9e4066Sahrens int error; 769fa9e4066Sahrens 770e9dbad6fSeschrock if ((error = get_nvlist(zc, &tryconfig)) != 0) 771fa9e4066Sahrens return (error); 772fa9e4066Sahrens 773fa9e4066Sahrens config = spa_tryimport(tryconfig); 774fa9e4066Sahrens 775fa9e4066Sahrens nvlist_free(tryconfig); 776fa9e4066Sahrens 777fa9e4066Sahrens if (config == NULL) 778fa9e4066Sahrens return (EINVAL); 779fa9e4066Sahrens 780e9dbad6fSeschrock error = put_nvlist(zc, config); 781fa9e4066Sahrens nvlist_free(config); 782fa9e4066Sahrens 783fa9e4066Sahrens return (error); 784fa9e4066Sahrens } 785fa9e4066Sahrens 786fa9e4066Sahrens static int 787fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 788fa9e4066Sahrens { 789fa9e4066Sahrens spa_t *spa; 790fa9e4066Sahrens int error; 791fa9e4066Sahrens 79206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 79306eeb2adSek return (error); 79406eeb2adSek 7953d7072f8Seschrock spa_config_enter(spa, RW_READER, FTAG); 79606eeb2adSek error = spa_scrub(spa, zc->zc_cookie, B_FALSE); 7973d7072f8Seschrock spa_config_exit(spa, FTAG); 79806eeb2adSek 79906eeb2adSek spa_close(spa, FTAG); 80006eeb2adSek 801fa9e4066Sahrens return (error); 802fa9e4066Sahrens } 803fa9e4066Sahrens 804fa9e4066Sahrens static int 805fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 806fa9e4066Sahrens { 807fa9e4066Sahrens spa_t *spa; 808fa9e4066Sahrens int error; 809fa9e4066Sahrens 810fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 811fa9e4066Sahrens if (error == 0) { 812fa9e4066Sahrens spa_freeze(spa); 813fa9e4066Sahrens spa_close(spa, FTAG); 814fa9e4066Sahrens } 815fa9e4066Sahrens return (error); 816fa9e4066Sahrens } 817fa9e4066Sahrens 818eaca9bbdSeschrock static int 819eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 820eaca9bbdSeschrock { 821eaca9bbdSeschrock spa_t *spa; 822eaca9bbdSeschrock int error; 823eaca9bbdSeschrock 82406eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 82506eeb2adSek return (error); 82606eeb2adSek 82706eeb2adSek spa_upgrade(spa); 82806eeb2adSek spa_close(spa, FTAG); 82906eeb2adSek 83006eeb2adSek return (error); 83106eeb2adSek } 83206eeb2adSek 83306eeb2adSek static int 83406eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 83506eeb2adSek { 83606eeb2adSek spa_t *spa; 83706eeb2adSek char *hist_buf; 83806eeb2adSek uint64_t size; 83906eeb2adSek int error; 84006eeb2adSek 84106eeb2adSek if ((size = zc->zc_history_len) == 0) 84206eeb2adSek return (EINVAL); 84306eeb2adSek 84406eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 84506eeb2adSek return (error); 84606eeb2adSek 847e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 848d7306b64Sek spa_close(spa, FTAG); 849d7306b64Sek return (ENOTSUP); 850d7306b64Sek } 851d7306b64Sek 85206eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 85306eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 85406eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 855ecd6cf80Smarks error = xcopyout(hist_buf, 856ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 85706eeb2adSek zc->zc_history_len); 85806eeb2adSek } 85906eeb2adSek 86006eeb2adSek spa_close(spa, FTAG); 86106eeb2adSek kmem_free(hist_buf, size); 86206eeb2adSek return (error); 86306eeb2adSek } 86406eeb2adSek 86555434c77Sek static int 86655434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 86755434c77Sek { 86855434c77Sek int error; 86955434c77Sek 870b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 87155434c77Sek return (error); 87255434c77Sek 87355434c77Sek return (0); 87455434c77Sek } 87555434c77Sek 87655434c77Sek static int 87755434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 87855434c77Sek { 87955434c77Sek objset_t *osp; 88055434c77Sek int error; 88155434c77Sek 88255434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 88355434c77Sek DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) 88455434c77Sek return (error); 88555434c77Sek 88655434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 88755434c77Sek sizeof (zc->zc_value)); 88855434c77Sek dmu_objset_close(osp); 88955434c77Sek 89055434c77Sek return (error); 89155434c77Sek } 89255434c77Sek 893fa9e4066Sahrens static int 894fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 895fa9e4066Sahrens { 896fa9e4066Sahrens spa_t *spa; 897fa9e4066Sahrens int error; 898fa9e4066Sahrens nvlist_t *config; 899fa9e4066Sahrens 900fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 901fa9e4066Sahrens if (error != 0) 902fa9e4066Sahrens return (error); 903fa9e4066Sahrens 904b1b8ab34Slling /* 905b1b8ab34Slling * A root pool with concatenated devices is not supported. 906b1b8ab34Slling * Thus, can not add a device to a root pool with one device. 907b1b8ab34Slling */ 908b1b8ab34Slling if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) { 909b1b8ab34Slling spa_close(spa, FTAG); 910b1b8ab34Slling return (EDOM); 911b1b8ab34Slling } 912b1b8ab34Slling 913e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) == 0) { 914fa9e4066Sahrens error = spa_vdev_add(spa, config); 915fa9e4066Sahrens nvlist_free(config); 916fa9e4066Sahrens } 917fa9e4066Sahrens spa_close(spa, FTAG); 918fa9e4066Sahrens return (error); 919fa9e4066Sahrens } 920fa9e4066Sahrens 921fa9e4066Sahrens static int 922fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 923fa9e4066Sahrens { 92499653d4eSeschrock spa_t *spa; 92599653d4eSeschrock int error; 92699653d4eSeschrock 92799653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 92899653d4eSeschrock if (error != 0) 92999653d4eSeschrock return (error); 93099653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 93199653d4eSeschrock spa_close(spa, FTAG); 93299653d4eSeschrock return (error); 933fa9e4066Sahrens } 934fa9e4066Sahrens 935fa9e4066Sahrens static int 9363d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 937fa9e4066Sahrens { 938fa9e4066Sahrens spa_t *spa; 939fa9e4066Sahrens int error; 9403d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 941fa9e4066Sahrens 94206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 943fa9e4066Sahrens return (error); 9443d7072f8Seschrock switch (zc->zc_cookie) { 9453d7072f8Seschrock case VDEV_STATE_ONLINE: 9463d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 9473d7072f8Seschrock break; 948fa9e4066Sahrens 9493d7072f8Seschrock case VDEV_STATE_OFFLINE: 9503d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 9513d7072f8Seschrock break; 952fa9e4066Sahrens 9533d7072f8Seschrock case VDEV_STATE_FAULTED: 9543d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 9553d7072f8Seschrock break; 9563d7072f8Seschrock 9573d7072f8Seschrock case VDEV_STATE_DEGRADED: 9583d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 9593d7072f8Seschrock break; 9603d7072f8Seschrock 9613d7072f8Seschrock default: 9623d7072f8Seschrock error = EINVAL; 9633d7072f8Seschrock } 9643d7072f8Seschrock zc->zc_cookie = newstate; 965fa9e4066Sahrens spa_close(spa, FTAG); 966fa9e4066Sahrens return (error); 967fa9e4066Sahrens } 968fa9e4066Sahrens 969fa9e4066Sahrens static int 970fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 971fa9e4066Sahrens { 972fa9e4066Sahrens spa_t *spa; 973fa9e4066Sahrens int replacing = zc->zc_cookie; 974fa9e4066Sahrens nvlist_t *config; 975fa9e4066Sahrens int error; 976fa9e4066Sahrens 97706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 978fa9e4066Sahrens return (error); 979fa9e4066Sahrens 980e9dbad6fSeschrock if ((error = get_nvlist(zc, &config)) == 0) { 981ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 982fa9e4066Sahrens nvlist_free(config); 983fa9e4066Sahrens } 984fa9e4066Sahrens 985fa9e4066Sahrens spa_close(spa, FTAG); 986fa9e4066Sahrens return (error); 987fa9e4066Sahrens } 988fa9e4066Sahrens 989fa9e4066Sahrens static int 990fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 991fa9e4066Sahrens { 992fa9e4066Sahrens spa_t *spa; 993fa9e4066Sahrens int error; 994fa9e4066Sahrens 99506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 996fa9e4066Sahrens return (error); 997fa9e4066Sahrens 998ea8dc4b6Seschrock error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 999fa9e4066Sahrens 1000fa9e4066Sahrens spa_close(spa, FTAG); 1001fa9e4066Sahrens return (error); 1002fa9e4066Sahrens } 1003fa9e4066Sahrens 1004c67d9675Seschrock static int 1005c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1006c67d9675Seschrock { 1007c67d9675Seschrock spa_t *spa; 1008e9dbad6fSeschrock char *path = zc->zc_value; 1009ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1010c67d9675Seschrock int error; 1011c67d9675Seschrock 1012c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1013c67d9675Seschrock if (error != 0) 1014c67d9675Seschrock return (error); 1015c67d9675Seschrock 1016c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1017c67d9675Seschrock spa_close(spa, FTAG); 1018c67d9675Seschrock return (error); 1019c67d9675Seschrock } 1020c67d9675Seschrock 1021fa9e4066Sahrens static int 1022fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1023fa9e4066Sahrens { 1024fa9e4066Sahrens objset_t *os = NULL; 1025fa9e4066Sahrens int error; 10267f7322feSeschrock nvlist_t *nv; 1027fa9e4066Sahrens 1028fa9e4066Sahrens retry: 1029fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1030fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 1031fa9e4066Sahrens if (error != 0) { 1032fa9e4066Sahrens /* 1033fa9e4066Sahrens * This is ugly: dmu_objset_open() can return EBUSY if 1034fa9e4066Sahrens * the objset is held exclusively. Fortunately this hold is 1035fa9e4066Sahrens * only for a short while, so we retry here. 1036fa9e4066Sahrens * This avoids user code having to handle EBUSY, 1037fa9e4066Sahrens * for example for a "zfs list". 1038fa9e4066Sahrens */ 1039fa9e4066Sahrens if (error == EBUSY) { 1040fa9e4066Sahrens delay(1); 1041fa9e4066Sahrens goto retry; 1042fa9e4066Sahrens } 1043fa9e4066Sahrens return (error); 1044fa9e4066Sahrens } 1045fa9e4066Sahrens 1046a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1047fa9e4066Sahrens 10485ad82045Snd if (zc->zc_nvlist_dst != 0 && 10497f7322feSeschrock (error = dsl_prop_get_all(os, &nv)) == 0) { 1050a2eea2e1Sahrens dmu_objset_stats(os, nv); 1051432f72fdSahrens /* 1052e7437265Sahrens * NB: {zpl,zvol}_get_stats() will read the objset contents, 1053432f72fdSahrens * which we aren't supposed to do with a 1054432f72fdSahrens * DS_MODE_STANDARD open, because it could be 1055432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1056432f72fdSahrens */ 1057e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1058e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1059e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1060e7437265Sahrens else if (dmu_objset_type(os) == DMU_OST_ZFS) 1061e7437265Sahrens (void) zfs_get_stats(os, nv); 1062e7437265Sahrens } 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 1183ecd6cf80Smarks /* 1184ecd6cf80Smarks * First validate permission to set all of the properties 1185ecd6cf80Smarks */ 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 1200ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 1201ecd6cf80Smarks ZFS_DELEG_PERM_USERPROP, cr); 1202ecd6cf80Smarks if (error) { 1203ecd6cf80Smarks return (EPERM); 1204ecd6cf80Smarks } 1205ecd6cf80Smarks continue; 1206e9dbad6fSeschrock } 1207fa9e4066Sahrens 1208e9dbad6fSeschrock /* 1209ecd6cf80Smarks * Check permissions for special properties 1210e9dbad6fSeschrock */ 1211ecd6cf80Smarks 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) { 1255ecd6cf80Smarks spa_t *spa; 1256c9431fa1Sahl 1257*40feaa91Sahrens if (spa_open(name, &spa, FTAG) == 0) { 1258c9431fa1Sahl if (spa_version(spa) < 1259e7437265Sahrens SPA_VERSION_GZIP_COMPRESSION) { 1260c9431fa1Sahl spa_close(spa, FTAG); 1261c9431fa1Sahl return (ENOTSUP); 1262c9431fa1Sahl } 1263c9431fa1Sahl 1264c9431fa1Sahl spa_close(spa, FTAG); 1265c9431fa1Sahl } 1266c9431fa1Sahl } 1267c9431fa1Sahl break; 1268*40feaa91Sahrens 1269*40feaa91Sahrens case ZFS_PROP_COPIES: 1270*40feaa91Sahrens { 1271*40feaa91Sahrens spa_t *spa; 1272*40feaa91Sahrens 1273*40feaa91Sahrens if (spa_open(name, &spa, FTAG) == 0) { 1274*40feaa91Sahrens if (spa_version(spa) < 1275*40feaa91Sahrens SPA_VERSION_DITTO_BLOCKS) { 1276*40feaa91Sahrens spa_close(spa, FTAG); 1277*40feaa91Sahrens return (ENOTSUP); 1278*40feaa91Sahrens } 1279*40feaa91Sahrens spa_close(spa, FTAG); 1280*40feaa91Sahrens } 1281*40feaa91Sahrens break; 1282*40feaa91Sahrens } 1283e9dbad6fSeschrock } 1284ecd6cf80Smarks if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0) 1285ecd6cf80Smarks return (error); 1286ecd6cf80Smarks } 1287ecd6cf80Smarks 1288ecd6cf80Smarks elem = NULL; 1289ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1290ecd6cf80Smarks propname = nvpair_name(elem); 1291ecd6cf80Smarks 1292ecd6cf80Smarks if ((prop = zfs_name_to_prop(propname)) == 1293ecd6cf80Smarks ZFS_PROP_INVAL) { 1294ecd6cf80Smarks 1295ecd6cf80Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 1296ecd6cf80Smarks error = dsl_prop_set(name, propname, 1, 1297ecd6cf80Smarks strlen(strval) + 1, strval); 1298ecd6cf80Smarks if (error == 0) 1299ecd6cf80Smarks continue; 1300ecd6cf80Smarks else 1301ecd6cf80Smarks return (error); 1302ecd6cf80Smarks } 1303e9dbad6fSeschrock 1304e9dbad6fSeschrock switch (prop) { 1305e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1306e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1307e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 1308e9dbad6fSeschrock return (error); 1309e9dbad6fSeschrock break; 1310e9dbad6fSeschrock 1311e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1312e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1313e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1314e9dbad6fSeschrock intval)) != 0) 1315e9dbad6fSeschrock return (error); 1316e9dbad6fSeschrock break; 1317e9dbad6fSeschrock 1318e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1319e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1320e7437265Sahrens (error = zvol_set_volsize(name, dev, intval)) != 0) 1321e9dbad6fSeschrock return (error); 1322e9dbad6fSeschrock break; 1323e9dbad6fSeschrock 1324e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1325e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1326e7437265Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 1327e7437265Sahrens return (error); 1328e7437265Sahrens break; 1329e7437265Sahrens 1330e7437265Sahrens case ZFS_PROP_VERSION: 1331e7437265Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1332e7437265Sahrens (error = zfs_set_version(name, intval)) != 0) 1333e9dbad6fSeschrock return (error); 1334e9dbad6fSeschrock break; 1335e9dbad6fSeschrock 1336e9dbad6fSeschrock default: 1337e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1338e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 1339e9dbad6fSeschrock prop_type_string) 1340e9dbad6fSeschrock return (EINVAL); 1341acd76fe5Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 1342acd76fe5Seschrock if ((error = dsl_prop_set(name, 1343e9dbad6fSeschrock nvpair_name(elem), 1, strlen(strval) + 1, 1344acd76fe5Seschrock strval)) != 0) 1345acd76fe5Seschrock return (error); 1346e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1347a2eea2e1Sahrens const char *unused; 1348a2eea2e1Sahrens 1349acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1350e9dbad6fSeschrock 1351e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 1352e9dbad6fSeschrock case prop_type_number: 1353e9dbad6fSeschrock break; 1354e9dbad6fSeschrock case prop_type_boolean: 1355e9dbad6fSeschrock if (intval > 1) 1356acd76fe5Seschrock return (EINVAL); 1357e9dbad6fSeschrock break; 1358e9dbad6fSeschrock case prop_type_string: 1359acd76fe5Seschrock return (EINVAL); 1360e9dbad6fSeschrock case prop_type_index: 1361acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 1362acd76fe5Seschrock intval, &unused) != 0) 1363acd76fe5Seschrock return (EINVAL); 1364e9dbad6fSeschrock break; 1365e9dbad6fSeschrock default: 1366e7437265Sahrens cmn_err(CE_PANIC, 1367e7437265Sahrens "unknown property type"); 1368e9dbad6fSeschrock break; 1369e9dbad6fSeschrock } 1370e9dbad6fSeschrock 1371acd76fe5Seschrock if ((error = dsl_prop_set(name, propname, 1372acd76fe5Seschrock 8, 1, &intval)) != 0) 1373acd76fe5Seschrock return (error); 1374e9dbad6fSeschrock } else { 1375e9dbad6fSeschrock return (EINVAL); 1376e9dbad6fSeschrock } 1377e9dbad6fSeschrock break; 1378e9dbad6fSeschrock } 1379e9dbad6fSeschrock } 1380e9dbad6fSeschrock 1381e9dbad6fSeschrock return (0); 1382fa9e4066Sahrens } 1383fa9e4066Sahrens 1384fa9e4066Sahrens static int 1385e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1386fa9e4066Sahrens { 1387e9dbad6fSeschrock nvlist_t *nvl; 1388e9dbad6fSeschrock int error; 1389e9dbad6fSeschrock zfs_prop_t prop; 1390e9dbad6fSeschrock 1391e9dbad6fSeschrock /* 1392e9dbad6fSeschrock * If zc_value is set, then this is an attempt to inherit a value. 1393e9dbad6fSeschrock * Otherwise, zc_nvlist refers to a list of properties to set. 1394e9dbad6fSeschrock */ 1395e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1396e9dbad6fSeschrock if (!zfs_prop_user(zc->zc_value) && 1397e9dbad6fSeschrock ((prop = zfs_name_to_prop(zc->zc_value)) == 1398e9dbad6fSeschrock ZFS_PROP_INVAL || 1399e9dbad6fSeschrock !zfs_prop_inheritable(prop))) 1400e9dbad6fSeschrock return (EINVAL); 1401e9dbad6fSeschrock 1402e9dbad6fSeschrock return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1403e9dbad6fSeschrock } 1404e9dbad6fSeschrock 1405e9dbad6fSeschrock if ((error = get_nvlist(zc, &nvl)) != 0) 1406e9dbad6fSeschrock return (error); 1407e9dbad6fSeschrock 1408e9dbad6fSeschrock error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev, 1409e9dbad6fSeschrock (cred_t *)(uintptr_t)zc->zc_cred, nvl); 1410ecd6cf80Smarks 1411e9dbad6fSeschrock nvlist_free(nvl); 1412e9dbad6fSeschrock return (error); 1413fa9e4066Sahrens } 1414fa9e4066Sahrens 1415b1b8ab34Slling static int 141611a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1417b1b8ab34Slling { 1418b1b8ab34Slling nvlist_t *nvl; 1419b1b8ab34Slling int error, reset_bootfs = 0; 1420b1b8ab34Slling uint64_t objnum; 1421ecd6cf80Smarks uint64_t intval; 1422b1b8ab34Slling zpool_prop_t prop; 1423b1b8ab34Slling nvpair_t *elem; 1424b1b8ab34Slling char *propname, *strval; 1425b1b8ab34Slling spa_t *spa; 1426b1b8ab34Slling vdev_t *rvdev; 1427b1b8ab34Slling char *vdev_type; 1428b1b8ab34Slling objset_t *os; 1429b1b8ab34Slling 1430b1b8ab34Slling if ((error = get_nvlist(zc, &nvl)) != 0) 1431b1b8ab34Slling return (error); 1432b1b8ab34Slling 1433b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1434b1b8ab34Slling nvlist_free(nvl); 1435b1b8ab34Slling return (error); 1436b1b8ab34Slling } 1437b1b8ab34Slling 1438e7437265Sahrens if (spa_version(spa) < SPA_VERSION_BOOTFS) { 1439b1b8ab34Slling nvlist_free(nvl); 1440b1b8ab34Slling spa_close(spa, FTAG); 1441b1b8ab34Slling return (ENOTSUP); 1442b1b8ab34Slling } 1443b1b8ab34Slling 1444b1b8ab34Slling elem = NULL; 1445b1b8ab34Slling while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1446b1b8ab34Slling 1447b1b8ab34Slling propname = nvpair_name(elem); 1448b1b8ab34Slling 1449b1b8ab34Slling if ((prop = zpool_name_to_prop(propname)) == 1450b1b8ab34Slling ZFS_PROP_INVAL) { 1451b1b8ab34Slling nvlist_free(nvl); 1452b1b8ab34Slling spa_close(spa, FTAG); 1453b1b8ab34Slling return (EINVAL); 1454b1b8ab34Slling } 1455b1b8ab34Slling 1456b1b8ab34Slling switch (prop) { 1457ecd6cf80Smarks case ZPOOL_PROP_DELEGATION: 1458ecd6cf80Smarks VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1459ecd6cf80Smarks if (intval > 1) 1460ecd6cf80Smarks error = EINVAL; 1461ecd6cf80Smarks break; 14623d7072f8Seschrock case ZPOOL_PROP_BOOTFS: 1463b1b8ab34Slling /* 1464b1b8ab34Slling * A bootable filesystem can not be on a RAIDZ pool 1465b1b8ab34Slling * nor a striped pool with more than 1 device. 1466b1b8ab34Slling */ 1467b1b8ab34Slling rvdev = spa->spa_root_vdev; 1468b1b8ab34Slling vdev_type = 1469b1b8ab34Slling rvdev->vdev_child[0]->vdev_ops->vdev_op_type; 1470b1b8ab34Slling if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 || 1471b1b8ab34Slling (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 && 1472b1b8ab34Slling rvdev->vdev_children > 1)) { 1473b1b8ab34Slling error = ENOTSUP; 1474b1b8ab34Slling break; 1475b1b8ab34Slling } 1476b1b8ab34Slling 1477b1b8ab34Slling reset_bootfs = 1; 1478b1b8ab34Slling 1479b1b8ab34Slling VERIFY(nvpair_value_string(elem, &strval) == 0); 1480b1b8ab34Slling if (strval == NULL || strval[0] == '\0') { 14813d7072f8Seschrock objnum = zpool_prop_default_numeric( 14823d7072f8Seschrock ZPOOL_PROP_BOOTFS); 1483b1b8ab34Slling break; 1484b1b8ab34Slling } 1485b1b8ab34Slling 1486b1b8ab34Slling if (error = dmu_objset_open(strval, DMU_OST_ZFS, 1487b1b8ab34Slling DS_MODE_STANDARD | DS_MODE_READONLY, &os)) 1488b1b8ab34Slling break; 1489b1b8ab34Slling objnum = dmu_objset_id(os); 1490b1b8ab34Slling dmu_objset_close(os); 1491b1b8ab34Slling break; 1492b1b8ab34Slling } 1493b1b8ab34Slling 1494b1b8ab34Slling if (error) 1495b1b8ab34Slling break; 1496b1b8ab34Slling } 1497b1b8ab34Slling if (error == 0) { 1498b1b8ab34Slling if (reset_bootfs) { 1499b1b8ab34Slling VERIFY(nvlist_remove(nvl, 15003d7072f8Seschrock zpool_prop_to_name(ZPOOL_PROP_BOOTFS), 1501b1b8ab34Slling DATA_TYPE_STRING) == 0); 1502b1b8ab34Slling VERIFY(nvlist_add_uint64(nvl, 15033d7072f8Seschrock zpool_prop_to_name(ZPOOL_PROP_BOOTFS), 15043d7072f8Seschrock objnum) == 0); 1505b1b8ab34Slling } 1506b1b8ab34Slling error = spa_set_props(spa, nvl); 1507b1b8ab34Slling } 1508b1b8ab34Slling 1509b1b8ab34Slling nvlist_free(nvl); 1510b1b8ab34Slling spa_close(spa, FTAG); 1511b1b8ab34Slling 1512b1b8ab34Slling return (error); 1513b1b8ab34Slling } 1514b1b8ab34Slling 1515b1b8ab34Slling static int 151611a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1517b1b8ab34Slling { 1518b1b8ab34Slling spa_t *spa; 1519b1b8ab34Slling int error; 1520b1b8ab34Slling nvlist_t *nvp = NULL; 1521b1b8ab34Slling 1522b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1523b1b8ab34Slling return (error); 1524b1b8ab34Slling 1525b1b8ab34Slling error = spa_get_props(spa, &nvp); 1526b1b8ab34Slling 1527b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1528b1b8ab34Slling error = put_nvlist(zc, nvp); 1529b1b8ab34Slling else 1530b1b8ab34Slling error = EFAULT; 1531b1b8ab34Slling 1532b1b8ab34Slling spa_close(spa, FTAG); 1533b1b8ab34Slling 1534b1b8ab34Slling if (nvp) 1535b1b8ab34Slling nvlist_free(nvp); 1536b1b8ab34Slling return (error); 1537b1b8ab34Slling } 1538b1b8ab34Slling 1539ecd6cf80Smarks static int 1540ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1541ecd6cf80Smarks { 1542ecd6cf80Smarks nvlist_t *nvp; 1543ecd6cf80Smarks int error; 1544ecd6cf80Smarks uint32_t uid; 1545ecd6cf80Smarks uint32_t gid; 1546ecd6cf80Smarks uint32_t *groups; 1547ecd6cf80Smarks uint_t group_cnt; 1548ecd6cf80Smarks cred_t *usercred; 1549ecd6cf80Smarks 1550ecd6cf80Smarks if ((error = get_nvlist(zc, &nvp)) != 0) { 1551ecd6cf80Smarks return (error); 1552ecd6cf80Smarks } 1553ecd6cf80Smarks 1554ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1555ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 1556ecd6cf80Smarks nvlist_free(nvp); 1557ecd6cf80Smarks return (EPERM); 1558ecd6cf80Smarks } 1559ecd6cf80Smarks 1560ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1561ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 1562ecd6cf80Smarks nvlist_free(nvp); 1563ecd6cf80Smarks return (EPERM); 1564ecd6cf80Smarks } 1565ecd6cf80Smarks 1566ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1567ecd6cf80Smarks &groups, &group_cnt)) != 0) { 1568ecd6cf80Smarks nvlist_free(nvp); 1569ecd6cf80Smarks return (EPERM); 1570ecd6cf80Smarks } 1571ecd6cf80Smarks usercred = cralloc(); 1572ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 1573ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1574ecd6cf80Smarks nvlist_free(nvp); 1575ecd6cf80Smarks crfree(usercred); 1576ecd6cf80Smarks return (EPERM); 1577ecd6cf80Smarks } 1578ecd6cf80Smarks nvlist_free(nvp); 1579ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 1580ecd6cf80Smarks ZFS_DELEG_PERM_SHAREISCSI, usercred); 1581ecd6cf80Smarks crfree(usercred); 1582ecd6cf80Smarks return (error); 1583ecd6cf80Smarks } 1584ecd6cf80Smarks 1585ecd6cf80Smarks static int 1586ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 1587ecd6cf80Smarks { 1588ecd6cf80Smarks int error; 1589ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 1590ecd6cf80Smarks cred_t *cr; 1591ecd6cf80Smarks 1592ecd6cf80Smarks if ((error = get_nvlist(zc, &fsaclnv)) != 0) 1593ecd6cf80Smarks return (error); 1594ecd6cf80Smarks 1595ecd6cf80Smarks /* 1596ecd6cf80Smarks * Verify nvlist is constructed correctly 1597ecd6cf80Smarks */ 1598ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1599ecd6cf80Smarks nvlist_free(fsaclnv); 1600ecd6cf80Smarks return (EINVAL); 1601ecd6cf80Smarks } 1602ecd6cf80Smarks 1603ecd6cf80Smarks /* 1604ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 1605ecd6cf80Smarks * that user is allowed to hand out each permission in 1606ecd6cf80Smarks * the nvlist(s) 1607ecd6cf80Smarks */ 1608ecd6cf80Smarks 1609ecd6cf80Smarks cr = (cred_t *)(uintptr_t)zc->zc_cred; 1610ecd6cf80Smarks error = secpolicy_zfs(cr); 1611ecd6cf80Smarks if (error) { 1612ecd6cf80Smarks if (zc->zc_perm_action == B_FALSE) 1613ecd6cf80Smarks error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr); 1614ecd6cf80Smarks else 1615ecd6cf80Smarks error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr); 1616ecd6cf80Smarks } 1617ecd6cf80Smarks 1618ecd6cf80Smarks if (error == 0) 1619ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1620ecd6cf80Smarks 1621ecd6cf80Smarks nvlist_free(fsaclnv); 1622ecd6cf80Smarks return (error); 1623ecd6cf80Smarks } 1624ecd6cf80Smarks 1625ecd6cf80Smarks static int 1626ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 1627ecd6cf80Smarks { 1628ecd6cf80Smarks nvlist_t *nvp; 1629ecd6cf80Smarks int error; 1630ecd6cf80Smarks 1631ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1632ecd6cf80Smarks error = put_nvlist(zc, nvp); 1633ecd6cf80Smarks nvlist_free(nvp); 1634ecd6cf80Smarks } 1635ecd6cf80Smarks 1636ecd6cf80Smarks return (error); 1637ecd6cf80Smarks } 1638ecd6cf80Smarks 1639fa9e4066Sahrens static int 1640fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1641fa9e4066Sahrens { 1642e9dbad6fSeschrock return (zvol_create_minor(zc->zc_name, zc->zc_dev)); 1643fa9e4066Sahrens } 1644fa9e4066Sahrens 1645fa9e4066Sahrens static int 1646fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1647fa9e4066Sahrens { 1648e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 1649fa9e4066Sahrens } 1650fa9e4066Sahrens 1651fa9e4066Sahrens /* 1652fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1653fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 1654fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 1655fa9e4066Sahrens */ 1656fa9e4066Sahrens static vfs_t * 1657fa9e4066Sahrens zfs_get_vfs(const char *resource) 1658fa9e4066Sahrens { 1659fa9e4066Sahrens struct vfs *vfsp; 1660fa9e4066Sahrens struct vfs *vfs_found = NULL; 1661fa9e4066Sahrens 1662fa9e4066Sahrens vfs_list_read_lock(); 1663fa9e4066Sahrens vfsp = rootvfs; 1664fa9e4066Sahrens do { 1665fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1666fa9e4066Sahrens VFS_HOLD(vfsp); 1667fa9e4066Sahrens vfs_found = vfsp; 1668fa9e4066Sahrens break; 1669fa9e4066Sahrens } 1670fa9e4066Sahrens vfsp = vfsp->vfs_next; 1671fa9e4066Sahrens } while (vfsp != rootvfs); 1672fa9e4066Sahrens vfs_list_unlock(); 1673fa9e4066Sahrens return (vfs_found); 1674fa9e4066Sahrens } 1675fa9e4066Sahrens 1676ecd6cf80Smarks /* ARGSUSED */ 1677fa9e4066Sahrens static void 1678ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1679fa9e4066Sahrens { 1680e7437265Sahrens nvlist_t *nvprops = arg; 1681e7437265Sahrens uint64_t version = ZPL_VERSION; 1682e7437265Sahrens 1683e7437265Sahrens (void) nvlist_lookup_uint64(nvprops, 1684e7437265Sahrens zfs_prop_to_name(ZFS_PROP_VERSION), &version); 1685e7437265Sahrens 1686e7437265Sahrens zfs_create_fs(os, cr, version, tx); 1687fa9e4066Sahrens } 1688fa9e4066Sahrens 1689fa9e4066Sahrens static int 1690fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 1691fa9e4066Sahrens { 1692fa9e4066Sahrens objset_t *clone; 1693fa9e4066Sahrens int error = 0; 1694ecd6cf80Smarks nvlist_t *nvprops = NULL; 1695ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 1696fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 1697fa9e4066Sahrens 1698fa9e4066Sahrens switch (type) { 1699fa9e4066Sahrens 1700fa9e4066Sahrens case DMU_OST_ZFS: 1701fa9e4066Sahrens cbfunc = zfs_create_cb; 1702fa9e4066Sahrens break; 1703fa9e4066Sahrens 1704fa9e4066Sahrens case DMU_OST_ZVOL: 1705fa9e4066Sahrens cbfunc = zvol_create_cb; 1706fa9e4066Sahrens break; 1707fa9e4066Sahrens 1708fa9e4066Sahrens default: 17091d452cf5Sahrens cbfunc = NULL; 1710fa9e4066Sahrens } 17111d452cf5Sahrens if (strchr(zc->zc_name, '@')) 17121d452cf5Sahrens return (EINVAL); 1713fa9e4066Sahrens 1714e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 1715ecd6cf80Smarks (error = get_nvlist(zc, &nvprops)) != 0) 1716e9dbad6fSeschrock return (error); 1717e9dbad6fSeschrock 1718e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1719fa9e4066Sahrens /* 1720fa9e4066Sahrens * We're creating a clone of an existing snapshot. 1721fa9e4066Sahrens */ 1722e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1723e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 1724ecd6cf80Smarks nvlist_free(nvprops); 1725fa9e4066Sahrens return (EINVAL); 1726e9dbad6fSeschrock } 1727fa9e4066Sahrens 1728e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 1729fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 1730e9dbad6fSeschrock if (error) { 1731ecd6cf80Smarks nvlist_free(nvprops); 1732fa9e4066Sahrens return (error); 1733e9dbad6fSeschrock } 1734fa9e4066Sahrens error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); 1735fa9e4066Sahrens dmu_objset_close(clone); 1736fa9e4066Sahrens } else { 1737e9dbad6fSeschrock if (cbfunc == NULL) { 1738ecd6cf80Smarks nvlist_free(nvprops); 17391d452cf5Sahrens return (EINVAL); 1740e9dbad6fSeschrock } 17415c5460e9Seschrock 1742e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 1743e9dbad6fSeschrock uint64_t volsize, volblocksize; 1744e9dbad6fSeschrock 1745ecd6cf80Smarks if (nvprops == NULL || 1746ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 1747e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1748e9dbad6fSeschrock &volsize) != 0) { 1749ecd6cf80Smarks nvlist_free(nvprops); 1750e9dbad6fSeschrock return (EINVAL); 1751e9dbad6fSeschrock } 1752e9dbad6fSeschrock 1753ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 1754e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1755e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 1756ecd6cf80Smarks nvlist_free(nvprops); 1757e9dbad6fSeschrock return (EINVAL); 1758e9dbad6fSeschrock } 1759e9dbad6fSeschrock 1760e9dbad6fSeschrock if (error != 0) 1761e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 1762e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 1763e9dbad6fSeschrock 1764e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 1765e9dbad6fSeschrock volblocksize)) != 0 || 1766e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 1767e9dbad6fSeschrock volblocksize)) != 0) { 1768ecd6cf80Smarks nvlist_free(nvprops); 17695c5460e9Seschrock return (error); 1770e9dbad6fSeschrock } 1771e7437265Sahrens } else if (type == DMU_OST_ZFS) { 1772e7437265Sahrens uint64_t version; 1773e7437265Sahrens 1774e7437265Sahrens if (0 == nvlist_lookup_uint64(nvprops, 1775e7437265Sahrens zfs_prop_to_name(ZFS_PROP_VERSION), &version) && 1776e7437265Sahrens (version < ZPL_VERSION_INITIAL || 1777e7437265Sahrens version > ZPL_VERSION)) { 1778e7437265Sahrens nvlist_free(nvprops); 1779e7437265Sahrens return (EINVAL); 1780e7437265Sahrens } 1781fa9e4066Sahrens } 1782e9dbad6fSeschrock 1783e9dbad6fSeschrock error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, 1784ecd6cf80Smarks nvprops); 1785fa9e4066Sahrens } 1786e9dbad6fSeschrock 1787e9dbad6fSeschrock /* 1788e9dbad6fSeschrock * It would be nice to do this atomically. 1789e9dbad6fSeschrock */ 1790e9dbad6fSeschrock if (error == 0) { 1791e9dbad6fSeschrock if ((error = zfs_set_prop_nvlist(zc->zc_name, 1792e9dbad6fSeschrock zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred, 1793ecd6cf80Smarks nvprops)) != 0) 1794e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 1795e9dbad6fSeschrock } 1796e9dbad6fSeschrock 1797ecd6cf80Smarks nvlist_free(nvprops); 1798fa9e4066Sahrens return (error); 1799fa9e4066Sahrens } 1800fa9e4066Sahrens 1801fa9e4066Sahrens static int 18021d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 1803fa9e4066Sahrens { 1804e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 18051d452cf5Sahrens return (EINVAL); 18061d452cf5Sahrens return (dmu_objset_snapshot(zc->zc_name, 1807e9dbad6fSeschrock zc->zc_value, zc->zc_cookie)); 18081d452cf5Sahrens } 1809fa9e4066Sahrens 1810cdf5b4caSmmusante int 18111d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 18121d452cf5Sahrens { 18131d452cf5Sahrens char *snapname = arg; 18141d452cf5Sahrens char *cp; 18150b69c2f0Sahrens vfs_t *vfsp = NULL; 18161d452cf5Sahrens 18171d452cf5Sahrens /* 18181d452cf5Sahrens * Snapshots (which are under .zfs control) must be unmounted 18191d452cf5Sahrens * before they can be destroyed. 18201d452cf5Sahrens */ 18211d452cf5Sahrens 18221d452cf5Sahrens if (snapname) { 18231d452cf5Sahrens (void) strcat(name, "@"); 18241d452cf5Sahrens (void) strcat(name, snapname); 18251d452cf5Sahrens vfsp = zfs_get_vfs(name); 18261d452cf5Sahrens cp = strchr(name, '@'); 18271d452cf5Sahrens *cp = '\0'; 18280b69c2f0Sahrens } else if (strchr(name, '@')) { 18291d452cf5Sahrens vfsp = zfs_get_vfs(name); 18301d452cf5Sahrens } 18311d452cf5Sahrens 18321d452cf5Sahrens if (vfsp) { 1833fa9e4066Sahrens /* 18341d452cf5Sahrens * Always force the unmount for snapshots. 1835fa9e4066Sahrens */ 18361d452cf5Sahrens int flag = MS_FORCE; 18371d452cf5Sahrens int err; 18381d452cf5Sahrens 18391d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 1840fa9e4066Sahrens VFS_RELE(vfsp); 18411d452cf5Sahrens return (err); 1842fa9e4066Sahrens } 18431d452cf5Sahrens VFS_RELE(vfsp); 18441d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 18451d452cf5Sahrens return (err); 18461d452cf5Sahrens } 18471d452cf5Sahrens return (0); 18481d452cf5Sahrens } 18491d452cf5Sahrens 18501d452cf5Sahrens static int 18511d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 18521d452cf5Sahrens { 18531d452cf5Sahrens int err; 18541d452cf5Sahrens 1855e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 18561d452cf5Sahrens return (EINVAL); 18571d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 1858e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 18591d452cf5Sahrens if (err) 18601d452cf5Sahrens return (err); 1861e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 18621d452cf5Sahrens } 18631d452cf5Sahrens 18641d452cf5Sahrens static int 18651d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 18661d452cf5Sahrens { 18671d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 18681d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 18691d452cf5Sahrens if (err) 18701d452cf5Sahrens return (err); 1871fa9e4066Sahrens } 1872fa9e4066Sahrens 1873fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 1874fa9e4066Sahrens } 1875fa9e4066Sahrens 1876fa9e4066Sahrens static int 1877fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 1878fa9e4066Sahrens { 1879fa9e4066Sahrens return (dmu_objset_rollback(zc->zc_name)); 1880fa9e4066Sahrens } 1881fa9e4066Sahrens 1882fa9e4066Sahrens static int 1883fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 1884fa9e4066Sahrens { 18857f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 1886cdf5b4caSmmusante 1887e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1888e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) 1889fa9e4066Sahrens return (EINVAL); 1890fa9e4066Sahrens 1891cdf5b4caSmmusante /* 1892cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 1893cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 1894cdf5b4caSmmusante * to unmount. 1895cdf5b4caSmmusante */ 1896cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 1897fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 18981d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 18991d452cf5Sahrens if (err) 19001d452cf5Sahrens return (err); 1901fa9e4066Sahrens } 1902fa9e4066Sahrens 1903cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 1904fa9e4066Sahrens } 1905fa9e4066Sahrens 1906fa9e4066Sahrens static int 1907fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc) 1908fa9e4066Sahrens { 1909fa9e4066Sahrens file_t *fp; 1910fa9e4066Sahrens int error, fd; 1911a2eea2e1Sahrens offset_t new_off; 1912fa9e4066Sahrens 19133ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 19143ccfa83cSahrens strchr(zc->zc_value, '@') == NULL) 19153ccfa83cSahrens return (EINVAL); 19163ccfa83cSahrens 1917fa9e4066Sahrens fd = zc->zc_cookie; 1918fa9e4066Sahrens fp = getf(fd); 1919fa9e4066Sahrens if (fp == NULL) 1920fa9e4066Sahrens return (EBADF); 1921e9dbad6fSeschrock error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record, 1922e9dbad6fSeschrock &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode, 192398579b20Snd fp->f_offset); 1924a2eea2e1Sahrens 1925a2eea2e1Sahrens new_off = fp->f_offset + zc->zc_cookie; 1926a2eea2e1Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0) 1927a2eea2e1Sahrens fp->f_offset = new_off; 1928a2eea2e1Sahrens 1929fa9e4066Sahrens releasef(fd); 1930fa9e4066Sahrens return (error); 1931fa9e4066Sahrens } 1932fa9e4066Sahrens 1933fa9e4066Sahrens static int 1934fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc) 1935fa9e4066Sahrens { 1936fa9e4066Sahrens objset_t *fromsnap = NULL; 1937fa9e4066Sahrens objset_t *tosnap; 1938fa9e4066Sahrens file_t *fp; 1939fa9e4066Sahrens int error; 1940fa9e4066Sahrens 1941fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1942fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); 1943fa9e4066Sahrens if (error) 1944fa9e4066Sahrens return (error); 1945fa9e4066Sahrens 1946e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1947a2eea2e1Sahrens char buf[MAXPATHLEN]; 1948a2eea2e1Sahrens char *cp; 1949a2eea2e1Sahrens 1950a2eea2e1Sahrens (void) strncpy(buf, zc->zc_name, sizeof (buf)); 1951a2eea2e1Sahrens cp = strchr(buf, '@'); 1952a2eea2e1Sahrens if (cp) 1953a2eea2e1Sahrens *(cp+1) = 0; 1954a2eea2e1Sahrens (void) strncat(buf, zc->zc_value, sizeof (buf)); 1955a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 1956fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); 1957fa9e4066Sahrens if (error) { 1958fa9e4066Sahrens dmu_objset_close(tosnap); 1959fa9e4066Sahrens return (error); 1960fa9e4066Sahrens } 1961fa9e4066Sahrens } 1962fa9e4066Sahrens 1963fa9e4066Sahrens fp = getf(zc->zc_cookie); 1964fa9e4066Sahrens if (fp == NULL) { 1965fa9e4066Sahrens dmu_objset_close(tosnap); 1966fa9e4066Sahrens if (fromsnap) 1967fa9e4066Sahrens dmu_objset_close(fromsnap); 1968fa9e4066Sahrens return (EBADF); 1969fa9e4066Sahrens } 1970fa9e4066Sahrens 1971fa9e4066Sahrens error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode); 1972fa9e4066Sahrens 1973fa9e4066Sahrens releasef(zc->zc_cookie); 1974fa9e4066Sahrens if (fromsnap) 1975fa9e4066Sahrens dmu_objset_close(fromsnap); 1976fa9e4066Sahrens dmu_objset_close(tosnap); 1977fa9e4066Sahrens return (error); 1978fa9e4066Sahrens } 1979fa9e4066Sahrens 1980ea8dc4b6Seschrock static int 1981ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 1982ea8dc4b6Seschrock { 1983ea8dc4b6Seschrock int id, error; 1984ea8dc4b6Seschrock 1985ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 1986ea8dc4b6Seschrock &zc->zc_inject_record); 1987ea8dc4b6Seschrock 1988ea8dc4b6Seschrock if (error == 0) 1989ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 1990ea8dc4b6Seschrock 1991ea8dc4b6Seschrock return (error); 1992ea8dc4b6Seschrock } 1993ea8dc4b6Seschrock 1994ea8dc4b6Seschrock static int 1995ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 1996ea8dc4b6Seschrock { 1997ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 1998ea8dc4b6Seschrock } 1999ea8dc4b6Seschrock 2000ea8dc4b6Seschrock static int 2001ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2002ea8dc4b6Seschrock { 2003ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2004ea8dc4b6Seschrock int error; 2005ea8dc4b6Seschrock 2006ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2007ea8dc4b6Seschrock &zc->zc_inject_record); 2008ea8dc4b6Seschrock 2009ea8dc4b6Seschrock zc->zc_guid = id; 2010ea8dc4b6Seschrock 2011ea8dc4b6Seschrock return (error); 2012ea8dc4b6Seschrock } 2013ea8dc4b6Seschrock 2014ea8dc4b6Seschrock static int 2015ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2016ea8dc4b6Seschrock { 2017ea8dc4b6Seschrock spa_t *spa; 2018ea8dc4b6Seschrock int error; 2019e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2020ea8dc4b6Seschrock 2021ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2022ea8dc4b6Seschrock return (error); 2023ea8dc4b6Seschrock 2024e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2025ea8dc4b6Seschrock &count); 2026ea8dc4b6Seschrock if (error == 0) 2027e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2028ea8dc4b6Seschrock else 2029e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2030ea8dc4b6Seschrock 2031ea8dc4b6Seschrock spa_close(spa, FTAG); 2032ea8dc4b6Seschrock 2033ea8dc4b6Seschrock return (error); 2034ea8dc4b6Seschrock } 2035ea8dc4b6Seschrock 2036ea8dc4b6Seschrock static int 2037ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2038ea8dc4b6Seschrock { 2039ea8dc4b6Seschrock spa_t *spa; 2040ea8dc4b6Seschrock vdev_t *vd; 2041ea8dc4b6Seschrock int error; 20423d7072f8Seschrock uint64_t txg; 2043ea8dc4b6Seschrock 2044ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2045ea8dc4b6Seschrock return (error); 2046ea8dc4b6Seschrock 20473d7072f8Seschrock txg = spa_vdev_enter(spa); 2048ea8dc4b6Seschrock 2049e9dbad6fSeschrock if (zc->zc_guid == 0) { 2050ea8dc4b6Seschrock vd = NULL; 2051e9dbad6fSeschrock } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { 20523d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, ENODEV); 2053ea8dc4b6Seschrock spa_close(spa, FTAG); 2054ea8dc4b6Seschrock return (ENODEV); 2055ea8dc4b6Seschrock } 2056ea8dc4b6Seschrock 2057ea8dc4b6Seschrock vdev_clear(spa, vd); 2058ea8dc4b6Seschrock 20593d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, 0); 2060ea8dc4b6Seschrock 2061ea8dc4b6Seschrock spa_close(spa, FTAG); 2062ea8dc4b6Seschrock 2063ea8dc4b6Seschrock return (0); 2064ea8dc4b6Seschrock } 2065ea8dc4b6Seschrock 206699653d4eSeschrock static int 206799653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 206899653d4eSeschrock { 20690b69c2f0Sahrens char *cp; 20700b69c2f0Sahrens 20710b69c2f0Sahrens /* 20720b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 20730b69c2f0Sahrens * it's easier. 20740b69c2f0Sahrens */ 2075e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 20760b69c2f0Sahrens if (cp) 20770b69c2f0Sahrens *cp = '\0'; 2078e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 20790b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 208099653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 208199653d4eSeschrock } 208299653d4eSeschrock 2083ecd6cf80Smarks /* 2084ecd6cf80Smarks * We don't want to have a hard dependency 2085ecd6cf80Smarks * against some special symbols in sharefs 2086ecd6cf80Smarks * and nfs. Determine them if needed when 2087ecd6cf80Smarks * the first file system is shared. 2088ecd6cf80Smarks * Neither sharefs or nfs are unloadable modules. 2089ecd6cf80Smarks */ 2090ecd6cf80Smarks int (*zexport_fs)(void *arg); 2091ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2092ecd6cf80Smarks 2093ecd6cf80Smarks int zfs_share_inited; 2094ecd6cf80Smarks ddi_modhandle_t nfs_mod; 2095ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 2096ecd6cf80Smarks kmutex_t zfs_share_lock; 2097ecd6cf80Smarks 2098ecd6cf80Smarks static int 2099ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 2100ecd6cf80Smarks { 2101ecd6cf80Smarks int error; 2102ecd6cf80Smarks int opcode; 2103ecd6cf80Smarks 2104ecd6cf80Smarks if (zfs_share_inited == 0) { 2105ecd6cf80Smarks mutex_enter(&zfs_share_lock); 2106ecd6cf80Smarks nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error); 2107ecd6cf80Smarks sharefs_mod = ddi_modopen("fs/sharefs", 2108ecd6cf80Smarks KRTLD_MODE_FIRST, &error); 2109ecd6cf80Smarks if (nfs_mod == NULL || sharefs_mod == NULL) { 2110ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2111ecd6cf80Smarks return (ENOSYS); 2112ecd6cf80Smarks } 2113ecd6cf80Smarks if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *)) 2114ecd6cf80Smarks ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) { 2115ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2116ecd6cf80Smarks return (ENOSYS); 2117ecd6cf80Smarks } 2118ecd6cf80Smarks 2119ecd6cf80Smarks if (zshare_fs == NULL && ((zshare_fs = 2120ecd6cf80Smarks (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2121ecd6cf80Smarks ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2122ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2123ecd6cf80Smarks return (ENOSYS); 2124ecd6cf80Smarks } 2125ecd6cf80Smarks zfs_share_inited = 1; 2126ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2127ecd6cf80Smarks } 2128ecd6cf80Smarks 2129ecd6cf80Smarks if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata)) 2130ecd6cf80Smarks return (error); 2131ecd6cf80Smarks 2132ecd6cf80Smarks opcode = (zc->zc_share.z_sharetype == B_TRUE) ? 2133ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 2134ecd6cf80Smarks 2135ecd6cf80Smarks error = zshare_fs(opcode, 2136ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 2137ecd6cf80Smarks zc->zc_share.z_sharemax); 2138ecd6cf80Smarks 2139ecd6cf80Smarks return (error); 2140ecd6cf80Smarks 2141ecd6cf80Smarks } 2142ecd6cf80Smarks 2143ecd6cf80Smarks /* 2144ecd6cf80Smarks * pool destroy and pool export don't log the history as part of zfsdev_ioctl, 2145ecd6cf80Smarks * but rather zfs_ioc_pool_create, and zfs_ioc_pool_export do the loggin 2146ecd6cf80Smarks * of those commands. 2147ecd6cf80Smarks */ 2148fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 2149e7437265Sahrens { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2150e7437265Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2151e7437265Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2152e7437265Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2153e7437265Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 2154e7437265Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2155e7437265Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2156e7437265Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2157e7437265Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2158e7437265Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2159e7437265Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2160e7437265Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2161e7437265Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2162e7437265Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2163e7437265Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2164e7437265Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2165e7437265Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2166e7437265Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2167ecd6cf80Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 2168e7437265Sahrens DATASET_NAME, B_FALSE }, 2169ecd6cf80Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 2170e7437265Sahrens DATASET_NAME, B_FALSE }, 2171e7437265Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 2172e7437265Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2173e7437265Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2174e7437265Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 2175e7437265Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2176e7437265Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 2177e7437265Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 2178e7437265Sahrens { zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 2179e7437265Sahrens { zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 2180e7437265Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2181e7437265Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2182e7437265Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2183e7437265Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 2184e7437265Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2185e7437265Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 2186e7437265Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2187e7437265Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 2188e7437265Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2189e7437265Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2190e7437265Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2191e7437265Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2192e7437265Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 2193e7437265Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2194ecd6cf80Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 2195e7437265Sahrens DATASET_NAME, B_FALSE }, 2196e7437265Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE } 2197fa9e4066Sahrens }; 2198fa9e4066Sahrens 2199fa9e4066Sahrens static int 2200fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2201fa9e4066Sahrens { 2202fa9e4066Sahrens zfs_cmd_t *zc; 2203fa9e4066Sahrens uint_t vec; 22041d452cf5Sahrens int error, rc; 2205fa9e4066Sahrens 2206fa9e4066Sahrens if (getminor(dev) != 0) 2207fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2208fa9e4066Sahrens 2209fa9e4066Sahrens vec = cmd - ZFS_IOC; 2210fa9e4066Sahrens 2211fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2212fa9e4066Sahrens return (EINVAL); 2213fa9e4066Sahrens 2214fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2215fa9e4066Sahrens 2216fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2217fa9e4066Sahrens 2218fa9e4066Sahrens if (error == 0) { 2219fa9e4066Sahrens zc->zc_cred = (uintptr_t)cr; 2220fa9e4066Sahrens zc->zc_dev = dev; 2221ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2222fa9e4066Sahrens } 2223fa9e4066Sahrens 2224fa9e4066Sahrens /* 2225fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2226fa9e4066Sahrens * the lower layers. 2227fa9e4066Sahrens */ 2228fa9e4066Sahrens if (error == 0) { 2229fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2230fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 2231e7437265Sahrens case POOL_NAME: 2232fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2233fa9e4066Sahrens error = EINVAL; 2234fa9e4066Sahrens break; 2235fa9e4066Sahrens 2236e7437265Sahrens case DATASET_NAME: 2237fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2238fa9e4066Sahrens error = EINVAL; 2239fa9e4066Sahrens break; 22405ad82045Snd 2241e7437265Sahrens case NO_NAME: 22425ad82045Snd break; 2243fa9e4066Sahrens } 2244fa9e4066Sahrens } 2245fa9e4066Sahrens 2246fa9e4066Sahrens if (error == 0) 2247fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2248fa9e4066Sahrens 22491d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 2250ecd6cf80Smarks if (error == 0) { 22511d452cf5Sahrens error = rc; 2252ecd6cf80Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 2253ecd6cf80Smarks zfs_log_history(zc); 2254ecd6cf80Smarks } 2255fa9e4066Sahrens 2256fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 2257fa9e4066Sahrens return (error); 2258fa9e4066Sahrens } 2259fa9e4066Sahrens 2260fa9e4066Sahrens static int 2261fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2262fa9e4066Sahrens { 2263fa9e4066Sahrens if (cmd != DDI_ATTACH) 2264fa9e4066Sahrens return (DDI_FAILURE); 2265fa9e4066Sahrens 2266fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 2267fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 2268fa9e4066Sahrens return (DDI_FAILURE); 2269fa9e4066Sahrens 2270fa9e4066Sahrens zfs_dip = dip; 2271fa9e4066Sahrens 2272fa9e4066Sahrens ddi_report_dev(dip); 2273fa9e4066Sahrens 2274fa9e4066Sahrens return (DDI_SUCCESS); 2275fa9e4066Sahrens } 2276fa9e4066Sahrens 2277fa9e4066Sahrens static int 2278fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2279fa9e4066Sahrens { 2280fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 2281fa9e4066Sahrens return (DDI_FAILURE); 2282fa9e4066Sahrens 2283fa9e4066Sahrens if (cmd != DDI_DETACH) 2284fa9e4066Sahrens return (DDI_FAILURE); 2285fa9e4066Sahrens 2286fa9e4066Sahrens zfs_dip = NULL; 2287fa9e4066Sahrens 2288fa9e4066Sahrens ddi_prop_remove_all(dip); 2289fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 2290fa9e4066Sahrens 2291fa9e4066Sahrens return (DDI_SUCCESS); 2292fa9e4066Sahrens } 2293fa9e4066Sahrens 2294fa9e4066Sahrens /*ARGSUSED*/ 2295fa9e4066Sahrens static int 2296fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2297fa9e4066Sahrens { 2298fa9e4066Sahrens switch (infocmd) { 2299fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 2300fa9e4066Sahrens *result = zfs_dip; 2301fa9e4066Sahrens return (DDI_SUCCESS); 2302fa9e4066Sahrens 2303fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 2304a0965f35Sbonwick *result = (void *)0; 2305fa9e4066Sahrens return (DDI_SUCCESS); 2306fa9e4066Sahrens } 2307fa9e4066Sahrens 2308fa9e4066Sahrens return (DDI_FAILURE); 2309fa9e4066Sahrens } 2310fa9e4066Sahrens 2311fa9e4066Sahrens /* 2312fa9e4066Sahrens * OK, so this is a little weird. 2313fa9e4066Sahrens * 2314fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 2315fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 2316fa9e4066Sahrens * 2317fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 2318fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 2319fa9e4066Sahrens */ 2320fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 2321fa9e4066Sahrens zvol_open, /* open */ 2322fa9e4066Sahrens zvol_close, /* close */ 2323fa9e4066Sahrens zvol_strategy, /* strategy */ 2324fa9e4066Sahrens nodev, /* print */ 2325fa9e4066Sahrens nodev, /* dump */ 2326fa9e4066Sahrens zvol_read, /* read */ 2327fa9e4066Sahrens zvol_write, /* write */ 2328fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 2329fa9e4066Sahrens nodev, /* devmap */ 2330fa9e4066Sahrens nodev, /* mmap */ 2331fa9e4066Sahrens nodev, /* segmap */ 2332fa9e4066Sahrens nochpoll, /* poll */ 2333fa9e4066Sahrens ddi_prop_op, /* prop_op */ 2334fa9e4066Sahrens NULL, /* streamtab */ 2335fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 2336fa9e4066Sahrens CB_REV, /* version */ 2337feb08c6bSbillm nodev, /* async read */ 2338feb08c6bSbillm nodev, /* async write */ 2339fa9e4066Sahrens }; 2340fa9e4066Sahrens 2341fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 2342fa9e4066Sahrens DEVO_REV, /* version */ 2343fa9e4066Sahrens 0, /* refcnt */ 2344fa9e4066Sahrens zfs_info, /* info */ 2345fa9e4066Sahrens nulldev, /* identify */ 2346fa9e4066Sahrens nulldev, /* probe */ 2347fa9e4066Sahrens zfs_attach, /* attach */ 2348fa9e4066Sahrens zfs_detach, /* detach */ 2349fa9e4066Sahrens nodev, /* reset */ 2350fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 2351fa9e4066Sahrens NULL /* no bus operations */ 2352fa9e4066Sahrens }; 2353fa9e4066Sahrens 2354fa9e4066Sahrens static struct modldrv zfs_modldrv = { 2355e7437265Sahrens &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, 2356e9dbad6fSeschrock &zfs_dev_ops 2357fa9e4066Sahrens }; 2358fa9e4066Sahrens 2359fa9e4066Sahrens static struct modlinkage modlinkage = { 2360fa9e4066Sahrens MODREV_1, 2361fa9e4066Sahrens (void *)&zfs_modlfs, 2362fa9e4066Sahrens (void *)&zfs_modldrv, 2363fa9e4066Sahrens NULL 2364fa9e4066Sahrens }; 2365fa9e4066Sahrens 2366fa9e4066Sahrens int 2367fa9e4066Sahrens _init(void) 2368fa9e4066Sahrens { 2369fa9e4066Sahrens int error; 2370fa9e4066Sahrens 2371a0965f35Sbonwick spa_init(FREAD | FWRITE); 2372a0965f35Sbonwick zfs_init(); 2373a0965f35Sbonwick zvol_init(); 2374a0965f35Sbonwick 2375a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 2376a0965f35Sbonwick zvol_fini(); 2377a0965f35Sbonwick zfs_fini(); 2378a0965f35Sbonwick spa_fini(); 2379fa9e4066Sahrens return (error); 2380a0965f35Sbonwick } 2381fa9e4066Sahrens 2382fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 2383fa9e4066Sahrens ASSERT(error == 0); 2384ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 2385fa9e4066Sahrens 2386fa9e4066Sahrens return (0); 2387fa9e4066Sahrens } 2388fa9e4066Sahrens 2389fa9e4066Sahrens int 2390fa9e4066Sahrens _fini(void) 2391fa9e4066Sahrens { 2392fa9e4066Sahrens int error; 2393fa9e4066Sahrens 2394ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 2395fa9e4066Sahrens return (EBUSY); 2396fa9e4066Sahrens 2397fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 2398fa9e4066Sahrens return (error); 2399fa9e4066Sahrens 2400fa9e4066Sahrens zvol_fini(); 2401fa9e4066Sahrens zfs_fini(); 2402fa9e4066Sahrens spa_fini(); 2403ecd6cf80Smarks if (zfs_share_inited) { 2404ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 2405ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 2406ecd6cf80Smarks } 2407fa9e4066Sahrens 2408fa9e4066Sahrens ldi_ident_release(zfs_li); 2409fa9e4066Sahrens zfs_li = NULL; 2410ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 2411fa9e4066Sahrens 2412fa9e4066Sahrens return (error); 2413fa9e4066Sahrens } 2414fa9e4066Sahrens 2415fa9e4066Sahrens int 2416fa9e4066Sahrens _info(struct modinfo *modinfop) 2417fa9e4066Sahrens { 2418fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 2419fa9e4066Sahrens } 2420