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> 66*f18faf3fSek #include <sys/zfs_vfsops.h> 67*f18faf3fSek #include <sys/dmu_objset.h> 68fa9e4066Sahrens 69fa9e4066Sahrens #include "zfs_namecheck.h" 70e9dbad6fSeschrock #include "zfs_prop.h" 71ecd6cf80Smarks #include "zfs_deleg.h" 72fa9e4066Sahrens 73fa9e4066Sahrens extern struct modlfs zfs_modlfs; 74fa9e4066Sahrens 75fa9e4066Sahrens extern void zfs_init(void); 76fa9e4066Sahrens extern void zfs_fini(void); 77fa9e4066Sahrens 78fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 79fa9e4066Sahrens dev_info_t *zfs_dip; 80fa9e4066Sahrens 81fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 82ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 83fa9e4066Sahrens 84fa9e4066Sahrens typedef struct zfs_ioc_vec { 85fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 86fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 87fa9e4066Sahrens enum { 88e7437265Sahrens NO_NAME, 89e7437265Sahrens POOL_NAME, 90e7437265Sahrens DATASET_NAME 91ecd6cf80Smarks } zvec_namecheck; 92ecd6cf80Smarks boolean_t zvec_his_log; 93fa9e4066Sahrens } zfs_ioc_vec_t; 94fa9e4066Sahrens 95fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 96fa9e4066Sahrens void 97fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 98fa9e4066Sahrens { 99fa9e4066Sahrens const char *newfile; 100fa9e4066Sahrens char buf[256]; 101fa9e4066Sahrens va_list adx; 102fa9e4066Sahrens 103fa9e4066Sahrens /* 104fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 105fa9e4066Sahrens */ 106fa9e4066Sahrens newfile = strrchr(file, '/'); 107fa9e4066Sahrens if (newfile != NULL) { 108fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 109fa9e4066Sahrens } else { 110fa9e4066Sahrens newfile = file; 111fa9e4066Sahrens } 112fa9e4066Sahrens 113fa9e4066Sahrens va_start(adx, fmt); 114fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 115fa9e4066Sahrens va_end(adx); 116fa9e4066Sahrens 117fa9e4066Sahrens /* 118fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 119fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 120fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 121fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 122fa9e4066Sahrens * arg0 = file name 123fa9e4066Sahrens * arg1 = function name 124fa9e4066Sahrens * arg2 = line number 125fa9e4066Sahrens * arg3 = message 126fa9e4066Sahrens */ 127fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 128fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 129fa9e4066Sahrens } 130fa9e4066Sahrens 131ecd6cf80Smarks static void 132228975ccSek history_str_free(char *buf) 133228975ccSek { 134228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 135228975ccSek } 136228975ccSek 137228975ccSek static char * 138228975ccSek history_str_get(zfs_cmd_t *zc) 139ecd6cf80Smarks { 14040feaa91Sahrens char *buf; 141ecd6cf80Smarks 142ecd6cf80Smarks if (zc->zc_history == NULL) 143228975ccSek return (NULL); 144e7437265Sahrens 145ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 146ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 147ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 148228975ccSek history_str_free(buf); 149228975ccSek return (NULL); 150ecd6cf80Smarks } 151ecd6cf80Smarks 152ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 153ecd6cf80Smarks 154228975ccSek return (buf); 155228975ccSek } 156ecd6cf80Smarks 157228975ccSek static void 158228975ccSek zfs_log_history(zfs_cmd_t *zc) 159228975ccSek { 160228975ccSek spa_t *spa; 161228975ccSek char *buf; 162ecd6cf80Smarks 163228975ccSek if ((buf = history_str_get(zc)) == NULL) 164228975ccSek return; 165228975ccSek 166228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 167228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 168228975ccSek (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 169228975ccSek spa_close(spa, FTAG); 170228975ccSek } 171228975ccSek history_str_free(buf); 172ecd6cf80Smarks } 173ecd6cf80Smarks 174fa9e4066Sahrens /* 175fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 176fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 177fa9e4066Sahrens */ 178fa9e4066Sahrens /* ARGSUSED */ 179fa9e4066Sahrens static int 180ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 181fa9e4066Sahrens { 182fa9e4066Sahrens return (0); 183fa9e4066Sahrens } 184fa9e4066Sahrens 185fa9e4066Sahrens /* 186fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 187fa9e4066Sahrens * no privileges, but must be visible in the local zone. 188fa9e4066Sahrens */ 189fa9e4066Sahrens /* ARGSUSED */ 190fa9e4066Sahrens static int 191ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 192fa9e4066Sahrens { 193fa9e4066Sahrens if (INGLOBALZONE(curproc) || 194ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 195fa9e4066Sahrens return (0); 196fa9e4066Sahrens 197fa9e4066Sahrens return (ENOENT); 198fa9e4066Sahrens } 199fa9e4066Sahrens 200fa9e4066Sahrens static int 201fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 202fa9e4066Sahrens { 203fa9e4066Sahrens uint64_t zoned; 204fa9e4066Sahrens int writable = 1; 205fa9e4066Sahrens 206fa9e4066Sahrens /* 207fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 208fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 209fa9e4066Sahrens */ 210fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 211fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 212fa9e4066Sahrens return (ENOENT); 213fa9e4066Sahrens 214fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 215fa9e4066Sahrens return (ENOENT); 216fa9e4066Sahrens 217fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 218fa9e4066Sahrens /* 219fa9e4066Sahrens * If the fs is zoned, only root can access it from the 220fa9e4066Sahrens * global zone. 221fa9e4066Sahrens */ 222fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 223fa9e4066Sahrens return (EPERM); 224fa9e4066Sahrens } else { 225fa9e4066Sahrens /* 226fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 227fa9e4066Sahrens */ 228fa9e4066Sahrens if (!zoned) 229fa9e4066Sahrens return (EPERM); 230fa9e4066Sahrens 231fa9e4066Sahrens /* must be writable by this zone */ 232fa9e4066Sahrens if (!writable) 233fa9e4066Sahrens return (EPERM); 234fa9e4066Sahrens } 235fa9e4066Sahrens return (0); 236fa9e4066Sahrens } 237fa9e4066Sahrens 238fa9e4066Sahrens int 239ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 240fa9e4066Sahrens { 241fa9e4066Sahrens int error; 242fa9e4066Sahrens 243ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 244ecd6cf80Smarks if (error == 0) { 245ecd6cf80Smarks error = secpolicy_zfs(cr); 246db870a07Sahrens if (error) 247ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 248ecd6cf80Smarks } 249ecd6cf80Smarks return (error); 250ecd6cf80Smarks } 251ecd6cf80Smarks 252ecd6cf80Smarks static int 253ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 254ecd6cf80Smarks { 255ecd6cf80Smarks /* 256ecd6cf80Smarks * Check permissions for special properties. 257ecd6cf80Smarks */ 258ecd6cf80Smarks switch (prop) { 259ecd6cf80Smarks case ZFS_PROP_ZONED: 260ecd6cf80Smarks /* 261ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 262ecd6cf80Smarks */ 263ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 264ecd6cf80Smarks return (EPERM); 265ecd6cf80Smarks break; 266ecd6cf80Smarks 267ecd6cf80Smarks case ZFS_PROP_QUOTA: 268ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 269ecd6cf80Smarks uint64_t zoned; 270ecd6cf80Smarks char setpoint[MAXNAMELEN]; 271ecd6cf80Smarks /* 272ecd6cf80Smarks * Unprivileged users are allowed to modify the 273ecd6cf80Smarks * quota on things *under* (ie. contained by) 274ecd6cf80Smarks * the thing they own. 275ecd6cf80Smarks */ 276ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 277ecd6cf80Smarks setpoint)) 278ecd6cf80Smarks return (EPERM); 279db870a07Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 280ecd6cf80Smarks return (EPERM); 281ecd6cf80Smarks } 282db870a07Sahrens break; 283ecd6cf80Smarks } 284ecd6cf80Smarks 28591ebeef5Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 286ecd6cf80Smarks } 287ecd6cf80Smarks 288ecd6cf80Smarks int 289ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 290ecd6cf80Smarks { 291ecd6cf80Smarks int error; 292ecd6cf80Smarks 293ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 294ecd6cf80Smarks if (error) 295fa9e4066Sahrens return (error); 296fa9e4066Sahrens 297ecd6cf80Smarks /* 298ecd6cf80Smarks * permission to set permissions will be evaluated later in 299ecd6cf80Smarks * dsl_deleg_can_allow() 300ecd6cf80Smarks */ 301ecd6cf80Smarks return (0); 302ecd6cf80Smarks } 303ecd6cf80Smarks 304ecd6cf80Smarks int 305ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 306ecd6cf80Smarks { 307ecd6cf80Smarks int error; 308ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 309ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 310ecd6cf80Smarks if (error == 0) 311ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 312ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 313ecd6cf80Smarks return (error); 314ecd6cf80Smarks } 315ecd6cf80Smarks 316ecd6cf80Smarks int 317ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 318ecd6cf80Smarks { 319ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 320ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 321ecd6cf80Smarks } 322ecd6cf80Smarks 323ecd6cf80Smarks int 324ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 325ecd6cf80Smarks { 326ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 327ecd6cf80Smarks return (EPERM); 328ecd6cf80Smarks 329ecd6cf80Smarks if (secpolicy_nfs(CRED()) == 0) { 330ecd6cf80Smarks return (0); 331ecd6cf80Smarks } else { 332ecd6cf80Smarks vnode_t *vp; 333ecd6cf80Smarks int error; 334ecd6cf80Smarks 335ecd6cf80Smarks if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 336ecd6cf80Smarks NO_FOLLOW, NULL, &vp)) != 0) 337ecd6cf80Smarks return (error); 338ecd6cf80Smarks 339ecd6cf80Smarks /* Now make sure mntpnt and dataset are ZFS */ 340ecd6cf80Smarks 341ecd6cf80Smarks if (vp->v_vfsp->vfs_fstype != zfsfstype || 342ecd6cf80Smarks (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 343ecd6cf80Smarks zc->zc_name) != 0)) { 344ecd6cf80Smarks VN_RELE(vp); 345ecd6cf80Smarks return (EPERM); 346ecd6cf80Smarks } 347ecd6cf80Smarks 348ecd6cf80Smarks VN_RELE(vp); 349ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 350ecd6cf80Smarks ZFS_DELEG_PERM_SHARE, cr)); 351ecd6cf80Smarks } 352fa9e4066Sahrens } 353fa9e4066Sahrens 354fa9e4066Sahrens static int 355ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 356fa9e4066Sahrens { 357fa9e4066Sahrens char *cp; 358fa9e4066Sahrens 359fa9e4066Sahrens /* 360fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 361fa9e4066Sahrens */ 362ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 363ecd6cf80Smarks cp = strrchr(parent, '@'); 364fa9e4066Sahrens if (cp != NULL) { 365fa9e4066Sahrens cp[0] = '\0'; 366fa9e4066Sahrens } else { 367ecd6cf80Smarks cp = strrchr(parent, '/'); 368fa9e4066Sahrens if (cp == NULL) 369fa9e4066Sahrens return (ENOENT); 370fa9e4066Sahrens cp[0] = '\0'; 371ecd6cf80Smarks } 372ecd6cf80Smarks 373ecd6cf80Smarks return (0); 374ecd6cf80Smarks } 375ecd6cf80Smarks 376ecd6cf80Smarks int 377ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 378ecd6cf80Smarks { 379ecd6cf80Smarks int error; 380ecd6cf80Smarks 381ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 382ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 383ecd6cf80Smarks return (error); 384ecd6cf80Smarks 385ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 386ecd6cf80Smarks } 387ecd6cf80Smarks 388ecd6cf80Smarks static int 389ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 390ecd6cf80Smarks { 391ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 392ecd6cf80Smarks } 393ecd6cf80Smarks 394ecd6cf80Smarks /* 395ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 396ecd6cf80Smarks */ 397ecd6cf80Smarks /* ARGSUSED */ 398ecd6cf80Smarks static int 399ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 400ecd6cf80Smarks { 401ecd6cf80Smarks return (secpolicy_zfs(cr)); 402ecd6cf80Smarks } 403ecd6cf80Smarks 404ecd6cf80Smarks int 405ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 406ecd6cf80Smarks { 407ecd6cf80Smarks char parentname[MAXNAMELEN]; 408ecd6cf80Smarks int error; 409ecd6cf80Smarks 410ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 411ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 412ecd6cf80Smarks return (error); 413ecd6cf80Smarks 414ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 415ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 416ecd6cf80Smarks return (error); 417ecd6cf80Smarks 418ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 419ecd6cf80Smarks sizeof (parentname))) != 0) 420ecd6cf80Smarks return (error); 421ecd6cf80Smarks 422ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 423ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 424ecd6cf80Smarks return (error); 425ecd6cf80Smarks 426ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 427ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 428ecd6cf80Smarks return (error); 429ecd6cf80Smarks 430ecd6cf80Smarks return (error); 431ecd6cf80Smarks } 432ecd6cf80Smarks 433ecd6cf80Smarks static int 434ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 435ecd6cf80Smarks { 436ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 437ecd6cf80Smarks } 438ecd6cf80Smarks 439ecd6cf80Smarks static int 440ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 441ecd6cf80Smarks { 442ecd6cf80Smarks char parentname[MAXNAMELEN]; 443ecd6cf80Smarks objset_t *clone; 444ecd6cf80Smarks int error; 445ecd6cf80Smarks 446ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 447ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 448ecd6cf80Smarks if (error) 449ecd6cf80Smarks return (error); 450ecd6cf80Smarks 451ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 452ecd6cf80Smarks DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 453ecd6cf80Smarks 454ecd6cf80Smarks if (error == 0) { 455ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 456ecd6cf80Smarks dsl_dir_t *dd; 457ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 458ecd6cf80Smarks 459ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 460ecd6cf80Smarks error = dsl_dataset_open_obj(dd->dd_pool, 461ecd6cf80Smarks dd->dd_phys->dd_clone_parent_obj, NULL, 462ecd6cf80Smarks DS_MODE_NONE, FTAG, &pclone); 463ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 464ecd6cf80Smarks if (error) { 465ecd6cf80Smarks dmu_objset_close(clone); 466ecd6cf80Smarks return (error); 467ecd6cf80Smarks } 468ecd6cf80Smarks 469ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 470ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 471ecd6cf80Smarks 472ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 473ecd6cf80Smarks dmu_objset_close(clone); 474ecd6cf80Smarks dsl_dataset_close(pclone, DS_MODE_NONE, FTAG); 475ecd6cf80Smarks if (error == 0) 476ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 477ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 478ecd6cf80Smarks } 479ecd6cf80Smarks return (error); 480ecd6cf80Smarks } 481ecd6cf80Smarks 482ecd6cf80Smarks static int 483ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 484ecd6cf80Smarks { 485ecd6cf80Smarks int error; 486ecd6cf80Smarks 487ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 488ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 489ecd6cf80Smarks return (error); 490ecd6cf80Smarks 491ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 492ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 493ecd6cf80Smarks return (error); 494ecd6cf80Smarks 495ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 496ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 497ecd6cf80Smarks } 498ecd6cf80Smarks 499ecd6cf80Smarks int 500ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 501ecd6cf80Smarks { 502ecd6cf80Smarks int error; 503ecd6cf80Smarks 504ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 505ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 506ecd6cf80Smarks return (error); 507ecd6cf80Smarks 508ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 509ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 510ecd6cf80Smarks 511ecd6cf80Smarks return (error); 512ecd6cf80Smarks } 513ecd6cf80Smarks 514ecd6cf80Smarks static int 515ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 516ecd6cf80Smarks { 517ecd6cf80Smarks 518ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 519ecd6cf80Smarks } 520ecd6cf80Smarks 521ecd6cf80Smarks static int 522ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 523ecd6cf80Smarks { 524ecd6cf80Smarks char parentname[MAXNAMELEN]; 525ecd6cf80Smarks int error; 526ecd6cf80Smarks 527ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 528ecd6cf80Smarks sizeof (parentname))) != 0) 529ecd6cf80Smarks return (error); 530fa9e4066Sahrens 531ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 532ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 533ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 534ecd6cf80Smarks return (error); 535fa9e4066Sahrens } 536fa9e4066Sahrens 537ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 538ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 539ecd6cf80Smarks return (error); 540ecd6cf80Smarks 541ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 542ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 543ecd6cf80Smarks 544ecd6cf80Smarks return (error); 545ecd6cf80Smarks } 546ecd6cf80Smarks 547ecd6cf80Smarks static int 548ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 549ecd6cf80Smarks { 550ecd6cf80Smarks int error; 551ecd6cf80Smarks 552ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 553ecd6cf80Smarks if (error) { 554ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 555ecd6cf80Smarks } 556ecd6cf80Smarks return (error); 557fa9e4066Sahrens } 558fa9e4066Sahrens 559fa9e4066Sahrens /* 560fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 561fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 562fa9e4066Sahrens */ 563fa9e4066Sahrens /* ARGSUSED */ 564fa9e4066Sahrens static int 565ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 566fa9e4066Sahrens { 567fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 568fa9e4066Sahrens return (EPERM); 569fa9e4066Sahrens 570fa9e4066Sahrens return (0); 571fa9e4066Sahrens } 572fa9e4066Sahrens 573ecd6cf80Smarks /* 574ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 575ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 576ecd6cf80Smarks * the minor nodes. 577ecd6cf80Smarks */ 578ecd6cf80Smarks static int 579ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 580ecd6cf80Smarks { 581ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 582ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 583ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 584ecd6cf80Smarks } 585ecd6cf80Smarks 586ecd6cf80Smarks return (0); 587ecd6cf80Smarks } 588ecd6cf80Smarks 589ea8dc4b6Seschrock /* 590ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 591ea8dc4b6Seschrock */ 592ea8dc4b6Seschrock /* ARGSUSED */ 593ea8dc4b6Seschrock static int 594ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 595ea8dc4b6Seschrock { 596ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 597ea8dc4b6Seschrock } 598ea8dc4b6Seschrock 599e45ce728Sahrens static int 600e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 601e45ce728Sahrens { 602e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 603e45ce728Sahrens 604990b4856Slling if (prop == ZPROP_INVAL) { 605e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 606e45ce728Sahrens return (EINVAL); 607e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 608e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 609e45ce728Sahrens } else { 610e45ce728Sahrens if (!zfs_prop_inheritable(prop)) 611e45ce728Sahrens return (EINVAL); 612e45ce728Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 613e45ce728Sahrens } 614e45ce728Sahrens } 615e45ce728Sahrens 616fa9e4066Sahrens /* 617fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 618fa9e4066Sahrens */ 619fa9e4066Sahrens static int 620990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 621fa9e4066Sahrens { 622fa9e4066Sahrens char *packed; 623fa9e4066Sahrens int error; 624990b4856Slling nvlist_t *list = NULL; 625fa9e4066Sahrens 626fa9e4066Sahrens /* 627e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 628fa9e4066Sahrens */ 629990b4856Slling if (size == 0) 630fa9e4066Sahrens return (EINVAL); 631fa9e4066Sahrens 632fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 633fa9e4066Sahrens 634990b4856Slling if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 635fa9e4066Sahrens kmem_free(packed, size); 636fa9e4066Sahrens return (error); 637fa9e4066Sahrens } 638fa9e4066Sahrens 639990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 640fa9e4066Sahrens kmem_free(packed, size); 641fa9e4066Sahrens return (error); 642fa9e4066Sahrens } 643fa9e4066Sahrens 644fa9e4066Sahrens kmem_free(packed, size); 645fa9e4066Sahrens 646990b4856Slling *nvp = list; 647fa9e4066Sahrens return (0); 648fa9e4066Sahrens } 649fa9e4066Sahrens 650e9dbad6fSeschrock static int 651e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 652e9dbad6fSeschrock { 653e9dbad6fSeschrock char *packed = NULL; 654e9dbad6fSeschrock size_t size; 655e9dbad6fSeschrock int error; 656e9dbad6fSeschrock 657e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 658e9dbad6fSeschrock 659e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 660e9dbad6fSeschrock error = ENOMEM; 661e9dbad6fSeschrock } else { 662da165920Smarks packed = kmem_alloc(size, KM_SLEEP); 663e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 664e9dbad6fSeschrock KM_SLEEP) == 0); 665e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 666e9dbad6fSeschrock size); 667e9dbad6fSeschrock kmem_free(packed, size); 668e9dbad6fSeschrock } 669e9dbad6fSeschrock 670e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 671e9dbad6fSeschrock return (error); 672e9dbad6fSeschrock } 673e9dbad6fSeschrock 674fa9e4066Sahrens static int 675fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 676fa9e4066Sahrens { 677fa9e4066Sahrens int error; 678990b4856Slling nvlist_t *config, *props = NULL; 679228975ccSek char *buf; 680fa9e4066Sahrens 681990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 682990b4856Slling &config)) 683fa9e4066Sahrens return (error); 6842a6b87f0Sek 685990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 686990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 687990b4856Slling nvlist_free(config); 688990b4856Slling return (error); 689990b4856Slling } 690990b4856Slling 6912a6b87f0Sek buf = history_str_get(zc); 692fa9e4066Sahrens 693990b4856Slling error = spa_create(zc->zc_name, config, props, buf); 694fa9e4066Sahrens 6952a6b87f0Sek if (buf != NULL) 6962a6b87f0Sek history_str_free(buf); 697990b4856Slling 698fa9e4066Sahrens nvlist_free(config); 699fa9e4066Sahrens 700990b4856Slling if (props) 701990b4856Slling nvlist_free(props); 702990b4856Slling 703fa9e4066Sahrens return (error); 704fa9e4066Sahrens } 705fa9e4066Sahrens 706fa9e4066Sahrens static int 707fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 708fa9e4066Sahrens { 709ecd6cf80Smarks int error; 710ecd6cf80Smarks zfs_log_history(zc); 711ecd6cf80Smarks error = spa_destroy(zc->zc_name); 712ecd6cf80Smarks return (error); 713fa9e4066Sahrens } 714fa9e4066Sahrens 715fa9e4066Sahrens static int 716fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 717fa9e4066Sahrens { 718fa9e4066Sahrens int error; 719990b4856Slling nvlist_t *config, *props = NULL; 720fa9e4066Sahrens uint64_t guid; 721fa9e4066Sahrens 722990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 723990b4856Slling &config)) != 0) 724990b4856Slling return (error); 725990b4856Slling 726990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 727990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 728990b4856Slling nvlist_free(config); 729fa9e4066Sahrens return (error); 730990b4856Slling } 731fa9e4066Sahrens 732fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 733ea8dc4b6Seschrock guid != zc->zc_guid) 734fa9e4066Sahrens error = EINVAL; 735fa9e4066Sahrens else 736990b4856Slling error = spa_import(zc->zc_name, config, props); 737fa9e4066Sahrens 738fa9e4066Sahrens nvlist_free(config); 739fa9e4066Sahrens 740990b4856Slling if (props) 741990b4856Slling nvlist_free(props); 742990b4856Slling 743fa9e4066Sahrens return (error); 744fa9e4066Sahrens } 745fa9e4066Sahrens 746fa9e4066Sahrens static int 747fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 748fa9e4066Sahrens { 749ecd6cf80Smarks int error; 750ecd6cf80Smarks zfs_log_history(zc); 751ecd6cf80Smarks error = spa_export(zc->zc_name, NULL); 752ecd6cf80Smarks return (error); 753fa9e4066Sahrens } 754fa9e4066Sahrens 755fa9e4066Sahrens static int 756fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 757fa9e4066Sahrens { 758fa9e4066Sahrens nvlist_t *configs; 759fa9e4066Sahrens int error; 760fa9e4066Sahrens 761fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 762fa9e4066Sahrens return (EEXIST); 763fa9e4066Sahrens 764e9dbad6fSeschrock error = put_nvlist(zc, configs); 765fa9e4066Sahrens 766fa9e4066Sahrens nvlist_free(configs); 767fa9e4066Sahrens 768fa9e4066Sahrens return (error); 769fa9e4066Sahrens } 770fa9e4066Sahrens 771fa9e4066Sahrens static int 772fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 773fa9e4066Sahrens { 774fa9e4066Sahrens nvlist_t *config; 775fa9e4066Sahrens int error; 776ea8dc4b6Seschrock int ret = 0; 777fa9e4066Sahrens 778e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 779e9dbad6fSeschrock sizeof (zc->zc_value)); 780fa9e4066Sahrens 781fa9e4066Sahrens if (config != NULL) { 782e9dbad6fSeschrock ret = put_nvlist(zc, config); 783fa9e4066Sahrens nvlist_free(config); 784ea8dc4b6Seschrock 785ea8dc4b6Seschrock /* 786ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 787ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 788ea8dc4b6Seschrock * in 'zc_cookie'. 789ea8dc4b6Seschrock */ 790ea8dc4b6Seschrock zc->zc_cookie = error; 791fa9e4066Sahrens } else { 792ea8dc4b6Seschrock ret = error; 793fa9e4066Sahrens } 794fa9e4066Sahrens 795ea8dc4b6Seschrock return (ret); 796fa9e4066Sahrens } 797fa9e4066Sahrens 798fa9e4066Sahrens /* 799fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 800fa9e4066Sahrens * user land knows which devices are available and overall pool health. 801fa9e4066Sahrens */ 802fa9e4066Sahrens static int 803fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 804fa9e4066Sahrens { 805fa9e4066Sahrens nvlist_t *tryconfig, *config; 806fa9e4066Sahrens int error; 807fa9e4066Sahrens 808990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 809990b4856Slling &tryconfig)) != 0) 810fa9e4066Sahrens return (error); 811fa9e4066Sahrens 812fa9e4066Sahrens config = spa_tryimport(tryconfig); 813fa9e4066Sahrens 814fa9e4066Sahrens nvlist_free(tryconfig); 815fa9e4066Sahrens 816fa9e4066Sahrens if (config == NULL) 817fa9e4066Sahrens return (EINVAL); 818fa9e4066Sahrens 819e9dbad6fSeschrock error = put_nvlist(zc, config); 820fa9e4066Sahrens nvlist_free(config); 821fa9e4066Sahrens 822fa9e4066Sahrens return (error); 823fa9e4066Sahrens } 824fa9e4066Sahrens 825fa9e4066Sahrens static int 826fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 827fa9e4066Sahrens { 828fa9e4066Sahrens spa_t *spa; 829fa9e4066Sahrens int error; 830fa9e4066Sahrens 83106eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 83206eeb2adSek return (error); 83306eeb2adSek 834bb8b5132Sek mutex_enter(&spa_namespace_lock); 83506eeb2adSek error = spa_scrub(spa, zc->zc_cookie, B_FALSE); 836bb8b5132Sek mutex_exit(&spa_namespace_lock); 83706eeb2adSek 83806eeb2adSek spa_close(spa, FTAG); 83906eeb2adSek 840fa9e4066Sahrens return (error); 841fa9e4066Sahrens } 842fa9e4066Sahrens 843fa9e4066Sahrens static int 844fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 845fa9e4066Sahrens { 846fa9e4066Sahrens spa_t *spa; 847fa9e4066Sahrens int error; 848fa9e4066Sahrens 849fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 850fa9e4066Sahrens if (error == 0) { 851fa9e4066Sahrens spa_freeze(spa); 852fa9e4066Sahrens spa_close(spa, FTAG); 853fa9e4066Sahrens } 854fa9e4066Sahrens return (error); 855fa9e4066Sahrens } 856fa9e4066Sahrens 857eaca9bbdSeschrock static int 858eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 859eaca9bbdSeschrock { 860eaca9bbdSeschrock spa_t *spa; 861eaca9bbdSeschrock int error; 862eaca9bbdSeschrock 86306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 86406eeb2adSek return (error); 86506eeb2adSek 866558d2d50Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 867558d2d50Slling spa_close(spa, FTAG); 868558d2d50Slling return (EINVAL); 869558d2d50Slling } 870558d2d50Slling 871990b4856Slling spa_upgrade(spa, zc->zc_cookie); 87206eeb2adSek spa_close(spa, FTAG); 87306eeb2adSek 87406eeb2adSek return (error); 87506eeb2adSek } 87606eeb2adSek 87706eeb2adSek static int 87806eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 87906eeb2adSek { 88006eeb2adSek spa_t *spa; 88106eeb2adSek char *hist_buf; 88206eeb2adSek uint64_t size; 88306eeb2adSek int error; 88406eeb2adSek 88506eeb2adSek if ((size = zc->zc_history_len) == 0) 88606eeb2adSek return (EINVAL); 88706eeb2adSek 88806eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 88906eeb2adSek return (error); 89006eeb2adSek 891e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 892d7306b64Sek spa_close(spa, FTAG); 893d7306b64Sek return (ENOTSUP); 894d7306b64Sek } 895d7306b64Sek 89606eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 89706eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 89806eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 899ecd6cf80Smarks error = xcopyout(hist_buf, 900ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 90106eeb2adSek zc->zc_history_len); 90206eeb2adSek } 90306eeb2adSek 90406eeb2adSek spa_close(spa, FTAG); 90506eeb2adSek kmem_free(hist_buf, size); 90606eeb2adSek return (error); 90706eeb2adSek } 90806eeb2adSek 90955434c77Sek static int 91055434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 91155434c77Sek { 91255434c77Sek int error; 91355434c77Sek 914b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 91555434c77Sek return (error); 91655434c77Sek 91755434c77Sek return (0); 91855434c77Sek } 91955434c77Sek 92055434c77Sek static int 92155434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 92255434c77Sek { 92355434c77Sek objset_t *osp; 92455434c77Sek int error; 92555434c77Sek 92655434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 92755434c77Sek DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) 92855434c77Sek return (error); 92955434c77Sek 93055434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 93155434c77Sek sizeof (zc->zc_value)); 93255434c77Sek dmu_objset_close(osp); 93355434c77Sek 93455434c77Sek return (error); 93555434c77Sek } 93655434c77Sek 937fa9e4066Sahrens static int 938fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 939fa9e4066Sahrens { 940fa9e4066Sahrens spa_t *spa; 941fa9e4066Sahrens int error; 942fa9e4066Sahrens nvlist_t *config; 943fa9e4066Sahrens 944fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 945fa9e4066Sahrens if (error != 0) 946fa9e4066Sahrens return (error); 947fa9e4066Sahrens 948b1b8ab34Slling /* 949b1b8ab34Slling * A root pool with concatenated devices is not supported. 950b1b8ab34Slling * Thus, can not add a device to a root pool with one device. 951b1b8ab34Slling */ 952b1b8ab34Slling if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) { 953b1b8ab34Slling spa_close(spa, FTAG); 954b1b8ab34Slling return (EDOM); 955b1b8ab34Slling } 956b1b8ab34Slling 957990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 958990b4856Slling &config)) == 0) { 959fa9e4066Sahrens error = spa_vdev_add(spa, config); 960fa9e4066Sahrens nvlist_free(config); 961fa9e4066Sahrens } 962fa9e4066Sahrens spa_close(spa, FTAG); 963fa9e4066Sahrens return (error); 964fa9e4066Sahrens } 965fa9e4066Sahrens 966fa9e4066Sahrens static int 967fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 968fa9e4066Sahrens { 96999653d4eSeschrock spa_t *spa; 97099653d4eSeschrock int error; 97199653d4eSeschrock 97299653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 97399653d4eSeschrock if (error != 0) 97499653d4eSeschrock return (error); 97599653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 97699653d4eSeschrock spa_close(spa, FTAG); 97799653d4eSeschrock return (error); 978fa9e4066Sahrens } 979fa9e4066Sahrens 980fa9e4066Sahrens static int 9813d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 982fa9e4066Sahrens { 983fa9e4066Sahrens spa_t *spa; 984fa9e4066Sahrens int error; 9853d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 986fa9e4066Sahrens 98706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 988fa9e4066Sahrens return (error); 9893d7072f8Seschrock switch (zc->zc_cookie) { 9903d7072f8Seschrock case VDEV_STATE_ONLINE: 9913d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 9923d7072f8Seschrock break; 993fa9e4066Sahrens 9943d7072f8Seschrock case VDEV_STATE_OFFLINE: 9953d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 9963d7072f8Seschrock break; 997fa9e4066Sahrens 9983d7072f8Seschrock case VDEV_STATE_FAULTED: 9993d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 10003d7072f8Seschrock break; 10013d7072f8Seschrock 10023d7072f8Seschrock case VDEV_STATE_DEGRADED: 10033d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 10043d7072f8Seschrock break; 10053d7072f8Seschrock 10063d7072f8Seschrock default: 10073d7072f8Seschrock error = EINVAL; 10083d7072f8Seschrock } 10093d7072f8Seschrock zc->zc_cookie = newstate; 1010fa9e4066Sahrens spa_close(spa, FTAG); 1011fa9e4066Sahrens return (error); 1012fa9e4066Sahrens } 1013fa9e4066Sahrens 1014fa9e4066Sahrens static int 1015fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1016fa9e4066Sahrens { 1017fa9e4066Sahrens spa_t *spa; 1018fa9e4066Sahrens int replacing = zc->zc_cookie; 1019fa9e4066Sahrens nvlist_t *config; 1020fa9e4066Sahrens int error; 1021fa9e4066Sahrens 102206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1023fa9e4066Sahrens return (error); 1024fa9e4066Sahrens 1025990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1026990b4856Slling &config)) == 0) { 1027ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1028fa9e4066Sahrens nvlist_free(config); 1029fa9e4066Sahrens } 1030fa9e4066Sahrens 1031fa9e4066Sahrens spa_close(spa, FTAG); 1032fa9e4066Sahrens return (error); 1033fa9e4066Sahrens } 1034fa9e4066Sahrens 1035fa9e4066Sahrens static int 1036fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1037fa9e4066Sahrens { 1038fa9e4066Sahrens spa_t *spa; 1039fa9e4066Sahrens int error; 1040fa9e4066Sahrens 104106eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1042fa9e4066Sahrens return (error); 1043fa9e4066Sahrens 1044ea8dc4b6Seschrock error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 1045fa9e4066Sahrens 1046fa9e4066Sahrens spa_close(spa, FTAG); 1047fa9e4066Sahrens return (error); 1048fa9e4066Sahrens } 1049fa9e4066Sahrens 1050c67d9675Seschrock static int 1051c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1052c67d9675Seschrock { 1053c67d9675Seschrock spa_t *spa; 1054e9dbad6fSeschrock char *path = zc->zc_value; 1055ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1056c67d9675Seschrock int error; 1057c67d9675Seschrock 1058c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1059c67d9675Seschrock if (error != 0) 1060c67d9675Seschrock return (error); 1061c67d9675Seschrock 1062c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1063c67d9675Seschrock spa_close(spa, FTAG); 1064c67d9675Seschrock return (error); 1065c67d9675Seschrock } 1066c67d9675Seschrock 1067fa9e4066Sahrens static int 1068fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1069fa9e4066Sahrens { 1070fa9e4066Sahrens objset_t *os = NULL; 1071fa9e4066Sahrens int error; 10727f7322feSeschrock nvlist_t *nv; 1073fa9e4066Sahrens 1074fa9e4066Sahrens retry: 1075fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1076fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 1077fa9e4066Sahrens if (error != 0) { 1078fa9e4066Sahrens /* 1079fa9e4066Sahrens * This is ugly: dmu_objset_open() can return EBUSY if 1080fa9e4066Sahrens * the objset is held exclusively. Fortunately this hold is 1081fa9e4066Sahrens * only for a short while, so we retry here. 1082fa9e4066Sahrens * This avoids user code having to handle EBUSY, 1083fa9e4066Sahrens * for example for a "zfs list". 1084fa9e4066Sahrens */ 1085fa9e4066Sahrens if (error == EBUSY) { 1086fa9e4066Sahrens delay(1); 1087fa9e4066Sahrens goto retry; 1088fa9e4066Sahrens } 1089fa9e4066Sahrens return (error); 1090fa9e4066Sahrens } 1091fa9e4066Sahrens 1092a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1093fa9e4066Sahrens 10945ad82045Snd if (zc->zc_nvlist_dst != 0 && 10957f7322feSeschrock (error = dsl_prop_get_all(os, &nv)) == 0) { 1096a2eea2e1Sahrens dmu_objset_stats(os, nv); 1097432f72fdSahrens /* 1098bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 1099432f72fdSahrens * which we aren't supposed to do with a 1100432f72fdSahrens * DS_MODE_STANDARD open, because it could be 1101432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1102432f72fdSahrens */ 1103e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1104e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1105e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1106e7437265Sahrens } 1107e9dbad6fSeschrock error = put_nvlist(zc, nv); 11087f7322feSeschrock nvlist_free(nv); 11097f7322feSeschrock } 1110fa9e4066Sahrens 1111e9dbad6fSeschrock spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); 1112ea8dc4b6Seschrock 1113fa9e4066Sahrens dmu_objset_close(os); 1114fa9e4066Sahrens return (error); 1115fa9e4066Sahrens } 1116fa9e4066Sahrens 1117bd00f61bSrm static int 1118bd00f61bSrm zfs_ioc_objset_version(zfs_cmd_t *zc) 1119bd00f61bSrm { 1120bd00f61bSrm objset_t *os = NULL; 1121bd00f61bSrm int error; 1122bd00f61bSrm 1123bd00f61bSrm retry: 1124bd00f61bSrm error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1125bd00f61bSrm DS_MODE_STANDARD | DS_MODE_READONLY, &os); 1126bd00f61bSrm if (error != 0) { 1127bd00f61bSrm /* 1128bd00f61bSrm * This is ugly: dmu_objset_open() can return EBUSY if 1129bd00f61bSrm * the objset is held exclusively. Fortunately this hold is 1130bd00f61bSrm * only for a short while, so we retry here. 1131bd00f61bSrm * This avoids user code having to handle EBUSY, 1132bd00f61bSrm * for example for a "zfs list". 1133bd00f61bSrm */ 1134bd00f61bSrm if (error == EBUSY) { 1135bd00f61bSrm delay(1); 1136bd00f61bSrm goto retry; 1137bd00f61bSrm } 1138bd00f61bSrm return (error); 1139bd00f61bSrm } 1140bd00f61bSrm 1141bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1142bd00f61bSrm 1143bd00f61bSrm /* 1144bd00f61bSrm * NB: zfs_get_version() will read the objset contents, 1145bd00f61bSrm * which we aren't supposed to do with a 1146bd00f61bSrm * DS_MODE_STANDARD open, because it could be 1147bd00f61bSrm * inconsistent. So this is a bit of a workaround... 1148bd00f61bSrm */ 1149bd00f61bSrm zc->zc_cookie = 0; 1150bd00f61bSrm if (!zc->zc_objset_stats.dds_inconsistent) 1151bd00f61bSrm if (dmu_objset_type(os) == DMU_OST_ZFS) 1152bd00f61bSrm (void) zfs_get_version(os, &zc->zc_cookie); 1153bd00f61bSrm 1154bd00f61bSrm dmu_objset_close(os); 1155bd00f61bSrm return (0); 1156bd00f61bSrm } 1157bd00f61bSrm 1158fa9e4066Sahrens static int 1159fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1160fa9e4066Sahrens { 116187e5029aSahrens objset_t *os; 1162fa9e4066Sahrens int error; 1163fa9e4066Sahrens char *p; 1164fa9e4066Sahrens 116587e5029aSahrens retry: 116687e5029aSahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 116787e5029aSahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 116887e5029aSahrens if (error != 0) { 116987e5029aSahrens /* 117087e5029aSahrens * This is ugly: dmu_objset_open() can return EBUSY if 117187e5029aSahrens * the objset is held exclusively. Fortunately this hold is 117287e5029aSahrens * only for a short while, so we retry here. 117387e5029aSahrens * This avoids user code having to handle EBUSY, 117487e5029aSahrens * for example for a "zfs list". 117587e5029aSahrens */ 117687e5029aSahrens if (error == EBUSY) { 117787e5029aSahrens delay(1); 117887e5029aSahrens goto retry; 117987e5029aSahrens } 118087e5029aSahrens if (error == ENOENT) 118187e5029aSahrens error = ESRCH; 118287e5029aSahrens return (error); 1183fa9e4066Sahrens } 1184fa9e4066Sahrens 1185fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1186fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1187fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1188fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1189fa9e4066Sahrens 1190fa9e4066Sahrens do { 119187e5029aSahrens error = dmu_dir_list_next(os, 119287e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 119387e5029aSahrens NULL, &zc->zc_cookie); 1194fa9e4066Sahrens if (error == ENOENT) 1195fa9e4066Sahrens error = ESRCH; 119687e5029aSahrens } while (error == 0 && !INGLOBALZONE(curproc) && 1197fa9e4066Sahrens !zone_dataset_visible(zc->zc_name, NULL)); 1198fa9e4066Sahrens 1199fa9e4066Sahrens /* 120087e5029aSahrens * If it's a hidden dataset (ie. with a '$' in its name), don't 120187e5029aSahrens * try to get stats for it. Userland will skip over it. 1202fa9e4066Sahrens */ 120387e5029aSahrens if (error == 0 && strchr(zc->zc_name, '$') == NULL) 120487e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1205fa9e4066Sahrens 120687e5029aSahrens dmu_objset_close(os); 1207fa9e4066Sahrens return (error); 1208fa9e4066Sahrens } 1209fa9e4066Sahrens 1210fa9e4066Sahrens static int 1211fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1212fa9e4066Sahrens { 121387e5029aSahrens objset_t *os; 1214fa9e4066Sahrens int error; 1215fa9e4066Sahrens 1216fa9e4066Sahrens retry: 121787e5029aSahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 121887e5029aSahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os); 121987e5029aSahrens if (error != 0) { 1220fa9e4066Sahrens /* 122187e5029aSahrens * This is ugly: dmu_objset_open() can return EBUSY if 1222fa9e4066Sahrens * the objset is held exclusively. Fortunately this hold is 1223fa9e4066Sahrens * only for a short while, so we retry here. 1224fa9e4066Sahrens * This avoids user code having to handle EBUSY, 122587e5029aSahrens * for example for a "zfs list". 1226fa9e4066Sahrens */ 1227fa9e4066Sahrens if (error == EBUSY) { 1228fa9e4066Sahrens delay(1); 1229fa9e4066Sahrens goto retry; 1230fa9e4066Sahrens } 1231fa9e4066Sahrens if (error == ENOENT) 123287e5029aSahrens error = ESRCH; 1233fa9e4066Sahrens return (error); 1234fa9e4066Sahrens } 1235fa9e4066Sahrens 1236b81d61a6Slling /* 1237b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1238b81d61a6Slling * so exit immediately. 1239b81d61a6Slling */ 1240b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 124187e5029aSahrens dmu_objset_close(os); 1242b81d61a6Slling return (ESRCH); 1243fa9e4066Sahrens } 1244fa9e4066Sahrens 124587e5029aSahrens error = dmu_snapshot_list_next(os, 124687e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 124787e5029aSahrens zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); 124887e5029aSahrens if (error == ENOENT) 124987e5029aSahrens error = ESRCH; 1250fa9e4066Sahrens 125187e5029aSahrens if (error == 0) 125287e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1253fa9e4066Sahrens 125487e5029aSahrens dmu_objset_close(os); 1255fa9e4066Sahrens return (error); 1256fa9e4066Sahrens } 1257fa9e4066Sahrens 1258fa9e4066Sahrens static int 125991ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1260fa9e4066Sahrens { 1261e9dbad6fSeschrock nvpair_t *elem; 1262e9dbad6fSeschrock int error; 1263e9dbad6fSeschrock uint64_t intval; 1264e9dbad6fSeschrock char *strval; 1265e9dbad6fSeschrock 1266ecd6cf80Smarks /* 1267ecd6cf80Smarks * First validate permission to set all of the properties 1268ecd6cf80Smarks */ 1269e9dbad6fSeschrock elem = NULL; 1270e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1271db870a07Sahrens const char *propname = nvpair_name(elem); 1272db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1273e9dbad6fSeschrock 1274990b4856Slling if (prop == ZPROP_INVAL) { 1275e9dbad6fSeschrock /* 1276e9dbad6fSeschrock * If this is a user-defined property, it must be a 1277e9dbad6fSeschrock * string, and there is no further validation to do. 1278e9dbad6fSeschrock */ 1279e9dbad6fSeschrock if (!zfs_prop_user(propname) || 1280e9dbad6fSeschrock nvpair_type(elem) != DATA_TYPE_STRING) 1281e9dbad6fSeschrock return (EINVAL); 1282e9dbad6fSeschrock 1283ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 128491ebeef5Sahrens ZFS_DELEG_PERM_USERPROP, CRED()); 1285db870a07Sahrens if (error) 1286db870a07Sahrens return (error); 1287ecd6cf80Smarks continue; 1288e9dbad6fSeschrock } 1289fa9e4066Sahrens 129091ebeef5Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1291db870a07Sahrens return (error); 1292db870a07Sahrens 1293e9dbad6fSeschrock /* 1294db870a07Sahrens * Check that this value is valid for this pool version 1295e9dbad6fSeschrock */ 1296e9dbad6fSeschrock switch (prop) { 1297c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1298c9431fa1Sahl /* 1299c9431fa1Sahl * If the user specified gzip compression, make sure 1300c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1301c9431fa1Sahl * we'll catch them later. 1302c9431fa1Sahl */ 1303c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1304c9431fa1Sahl nvpair_value_uint64(elem, &intval) == 0 && 1305c9431fa1Sahl intval >= ZIO_COMPRESS_GZIP_1 && 1306c9431fa1Sahl intval <= ZIO_COMPRESS_GZIP_9) { 1307ecd6cf80Smarks spa_t *spa; 1308c9431fa1Sahl 130940feaa91Sahrens if (spa_open(name, &spa, FTAG) == 0) { 1310c9431fa1Sahl if (spa_version(spa) < 1311e7437265Sahrens SPA_VERSION_GZIP_COMPRESSION) { 1312c9431fa1Sahl spa_close(spa, FTAG); 1313c9431fa1Sahl return (ENOTSUP); 1314c9431fa1Sahl } 1315c9431fa1Sahl 1316c9431fa1Sahl spa_close(spa, FTAG); 1317c9431fa1Sahl } 1318c9431fa1Sahl } 1319c9431fa1Sahl break; 132040feaa91Sahrens 132140feaa91Sahrens case ZFS_PROP_COPIES: 132240feaa91Sahrens { 132340feaa91Sahrens spa_t *spa; 132440feaa91Sahrens 132540feaa91Sahrens if (spa_open(name, &spa, FTAG) == 0) { 132640feaa91Sahrens if (spa_version(spa) < 132740feaa91Sahrens SPA_VERSION_DITTO_BLOCKS) { 132840feaa91Sahrens spa_close(spa, FTAG); 132940feaa91Sahrens return (ENOTSUP); 133040feaa91Sahrens } 133140feaa91Sahrens spa_close(spa, FTAG); 133240feaa91Sahrens } 133340feaa91Sahrens break; 133440feaa91Sahrens } 1335e9dbad6fSeschrock } 1336ecd6cf80Smarks } 1337ecd6cf80Smarks 1338ecd6cf80Smarks elem = NULL; 1339ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1340db870a07Sahrens const char *propname = nvpair_name(elem); 1341db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1342ecd6cf80Smarks 1343990b4856Slling if (prop == ZPROP_INVAL) { 1344ecd6cf80Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 1345ecd6cf80Smarks error = dsl_prop_set(name, propname, 1, 1346ecd6cf80Smarks strlen(strval) + 1, strval); 1347ecd6cf80Smarks if (error == 0) 1348ecd6cf80Smarks continue; 1349ecd6cf80Smarks else 1350ecd6cf80Smarks return (error); 1351ecd6cf80Smarks } 1352e9dbad6fSeschrock 1353e9dbad6fSeschrock switch (prop) { 1354e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1355e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1356e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 1357e9dbad6fSeschrock return (error); 1358e9dbad6fSeschrock break; 1359e9dbad6fSeschrock 1360e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1361e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1362e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1363e9dbad6fSeschrock intval)) != 0) 1364e9dbad6fSeschrock return (error); 1365e9dbad6fSeschrock break; 1366e9dbad6fSeschrock 1367e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1368e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 136991ebeef5Sahrens (error = zvol_set_volsize(name, 137091ebeef5Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 1371e9dbad6fSeschrock return (error); 1372e9dbad6fSeschrock break; 1373e9dbad6fSeschrock 1374e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1375e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1376e7437265Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 1377e7437265Sahrens return (error); 1378e7437265Sahrens break; 1379e7437265Sahrens 1380e7437265Sahrens case ZFS_PROP_VERSION: 1381e7437265Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1382e7437265Sahrens (error = zfs_set_version(name, intval)) != 0) 1383e9dbad6fSeschrock return (error); 1384e9dbad6fSeschrock break; 1385e9dbad6fSeschrock 1386e9dbad6fSeschrock default: 1387e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1388e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 138991ebeef5Sahrens PROP_TYPE_STRING) 1390e9dbad6fSeschrock return (EINVAL); 1391acd76fe5Seschrock VERIFY(nvpair_value_string(elem, &strval) == 0); 1392acd76fe5Seschrock if ((error = dsl_prop_set(name, 1393e9dbad6fSeschrock nvpair_name(elem), 1, strlen(strval) + 1, 1394acd76fe5Seschrock strval)) != 0) 1395acd76fe5Seschrock return (error); 1396e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1397a2eea2e1Sahrens const char *unused; 1398a2eea2e1Sahrens 1399acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1400e9dbad6fSeschrock 1401e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 140291ebeef5Sahrens case PROP_TYPE_NUMBER: 1403e9dbad6fSeschrock break; 140491ebeef5Sahrens case PROP_TYPE_STRING: 1405acd76fe5Seschrock return (EINVAL); 140691ebeef5Sahrens case PROP_TYPE_INDEX: 1407acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 1408acd76fe5Seschrock intval, &unused) != 0) 1409acd76fe5Seschrock return (EINVAL); 1410e9dbad6fSeschrock break; 1411e9dbad6fSeschrock default: 1412e7437265Sahrens cmn_err(CE_PANIC, 1413e7437265Sahrens "unknown property type"); 1414e9dbad6fSeschrock break; 1415e9dbad6fSeschrock } 1416e9dbad6fSeschrock 1417acd76fe5Seschrock if ((error = dsl_prop_set(name, propname, 1418acd76fe5Seschrock 8, 1, &intval)) != 0) 1419acd76fe5Seschrock return (error); 1420e9dbad6fSeschrock } else { 1421e9dbad6fSeschrock return (EINVAL); 1422e9dbad6fSeschrock } 1423e9dbad6fSeschrock break; 1424e9dbad6fSeschrock } 1425e9dbad6fSeschrock } 1426e9dbad6fSeschrock 1427e9dbad6fSeschrock return (0); 1428fa9e4066Sahrens } 1429fa9e4066Sahrens 1430fa9e4066Sahrens static int 1431e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1432fa9e4066Sahrens { 1433e9dbad6fSeschrock nvlist_t *nvl; 1434e9dbad6fSeschrock int error; 1435e9dbad6fSeschrock 1436990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1437990b4856Slling &nvl)) != 0) 1438e9dbad6fSeschrock return (error); 1439e9dbad6fSeschrock 144091ebeef5Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1441ecd6cf80Smarks 1442e9dbad6fSeschrock nvlist_free(nvl); 1443e9dbad6fSeschrock return (error); 1444fa9e4066Sahrens } 1445fa9e4066Sahrens 1446e45ce728Sahrens static int 1447e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 1448e45ce728Sahrens { 1449e45ce728Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 1450e45ce728Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1451e45ce728Sahrens } 1452e45ce728Sahrens 1453b1b8ab34Slling static int 145411a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1455b1b8ab34Slling { 1456990b4856Slling nvlist_t *props; 1457b1b8ab34Slling spa_t *spa; 1458990b4856Slling int error; 1459b1b8ab34Slling 1460990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1461990b4856Slling &props))) 1462b1b8ab34Slling return (error); 1463b1b8ab34Slling 1464b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1465990b4856Slling nvlist_free(props); 1466b1b8ab34Slling return (error); 1467b1b8ab34Slling } 1468b1b8ab34Slling 1469990b4856Slling error = spa_prop_set(spa, props); 1470b1b8ab34Slling 1471990b4856Slling nvlist_free(props); 1472b1b8ab34Slling spa_close(spa, FTAG); 1473b1b8ab34Slling 1474b1b8ab34Slling return (error); 1475b1b8ab34Slling } 1476b1b8ab34Slling 1477b1b8ab34Slling static int 147811a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1479b1b8ab34Slling { 1480b1b8ab34Slling spa_t *spa; 1481b1b8ab34Slling int error; 1482b1b8ab34Slling nvlist_t *nvp = NULL; 1483b1b8ab34Slling 1484b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1485b1b8ab34Slling return (error); 1486b1b8ab34Slling 1487990b4856Slling error = spa_prop_get(spa, &nvp); 1488b1b8ab34Slling 1489b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1490b1b8ab34Slling error = put_nvlist(zc, nvp); 1491b1b8ab34Slling else 1492b1b8ab34Slling error = EFAULT; 1493b1b8ab34Slling 1494b1b8ab34Slling spa_close(spa, FTAG); 1495b1b8ab34Slling 1496b1b8ab34Slling if (nvp) 1497b1b8ab34Slling nvlist_free(nvp); 1498b1b8ab34Slling return (error); 1499b1b8ab34Slling } 1500b1b8ab34Slling 1501ecd6cf80Smarks static int 1502ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1503ecd6cf80Smarks { 1504ecd6cf80Smarks nvlist_t *nvp; 1505ecd6cf80Smarks int error; 1506ecd6cf80Smarks uint32_t uid; 1507ecd6cf80Smarks uint32_t gid; 1508ecd6cf80Smarks uint32_t *groups; 1509ecd6cf80Smarks uint_t group_cnt; 1510ecd6cf80Smarks cred_t *usercred; 1511ecd6cf80Smarks 1512990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1513990b4856Slling &nvp)) != 0) { 1514ecd6cf80Smarks return (error); 1515ecd6cf80Smarks } 1516ecd6cf80Smarks 1517ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1518ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 1519ecd6cf80Smarks nvlist_free(nvp); 1520ecd6cf80Smarks return (EPERM); 1521ecd6cf80Smarks } 1522ecd6cf80Smarks 1523ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1524ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 1525ecd6cf80Smarks nvlist_free(nvp); 1526ecd6cf80Smarks return (EPERM); 1527ecd6cf80Smarks } 1528ecd6cf80Smarks 1529ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1530ecd6cf80Smarks &groups, &group_cnt)) != 0) { 1531ecd6cf80Smarks nvlist_free(nvp); 1532ecd6cf80Smarks return (EPERM); 1533ecd6cf80Smarks } 1534ecd6cf80Smarks usercred = cralloc(); 1535ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 1536ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1537ecd6cf80Smarks nvlist_free(nvp); 1538ecd6cf80Smarks crfree(usercred); 1539ecd6cf80Smarks return (EPERM); 1540ecd6cf80Smarks } 1541ecd6cf80Smarks nvlist_free(nvp); 1542ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 154391ebeef5Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 1544ecd6cf80Smarks crfree(usercred); 1545ecd6cf80Smarks return (error); 1546ecd6cf80Smarks } 1547ecd6cf80Smarks 1548ecd6cf80Smarks static int 1549ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 1550ecd6cf80Smarks { 1551ecd6cf80Smarks int error; 1552ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 1553ecd6cf80Smarks 1554990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1555990b4856Slling &fsaclnv)) != 0) 1556ecd6cf80Smarks return (error); 1557ecd6cf80Smarks 1558ecd6cf80Smarks /* 1559ecd6cf80Smarks * Verify nvlist is constructed correctly 1560ecd6cf80Smarks */ 1561ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1562ecd6cf80Smarks nvlist_free(fsaclnv); 1563ecd6cf80Smarks return (EINVAL); 1564ecd6cf80Smarks } 1565ecd6cf80Smarks 1566ecd6cf80Smarks /* 1567ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 1568ecd6cf80Smarks * that user is allowed to hand out each permission in 1569ecd6cf80Smarks * the nvlist(s) 1570ecd6cf80Smarks */ 1571ecd6cf80Smarks 157291ebeef5Sahrens error = secpolicy_zfs(CRED()); 1573ecd6cf80Smarks if (error) { 157491ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 157591ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 157691ebeef5Sahrens fsaclnv, CRED()); 157791ebeef5Sahrens } else { 157891ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 157991ebeef5Sahrens fsaclnv, CRED()); 158091ebeef5Sahrens } 1581ecd6cf80Smarks } 1582ecd6cf80Smarks 1583ecd6cf80Smarks if (error == 0) 1584ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1585ecd6cf80Smarks 1586ecd6cf80Smarks nvlist_free(fsaclnv); 1587ecd6cf80Smarks return (error); 1588ecd6cf80Smarks } 1589ecd6cf80Smarks 1590ecd6cf80Smarks static int 1591ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 1592ecd6cf80Smarks { 1593ecd6cf80Smarks nvlist_t *nvp; 1594ecd6cf80Smarks int error; 1595ecd6cf80Smarks 1596ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1597ecd6cf80Smarks error = put_nvlist(zc, nvp); 1598ecd6cf80Smarks nvlist_free(nvp); 1599ecd6cf80Smarks } 1600ecd6cf80Smarks 1601ecd6cf80Smarks return (error); 1602ecd6cf80Smarks } 1603ecd6cf80Smarks 1604fa9e4066Sahrens static int 1605fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1606fa9e4066Sahrens { 160791ebeef5Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1608fa9e4066Sahrens } 1609fa9e4066Sahrens 1610fa9e4066Sahrens static int 1611fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1612fa9e4066Sahrens { 1613e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 1614fa9e4066Sahrens } 1615fa9e4066Sahrens 1616fa9e4066Sahrens /* 1617fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1618fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 1619fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 1620fa9e4066Sahrens */ 1621fa9e4066Sahrens static vfs_t * 1622fa9e4066Sahrens zfs_get_vfs(const char *resource) 1623fa9e4066Sahrens { 1624fa9e4066Sahrens struct vfs *vfsp; 1625fa9e4066Sahrens struct vfs *vfs_found = NULL; 1626fa9e4066Sahrens 1627fa9e4066Sahrens vfs_list_read_lock(); 1628fa9e4066Sahrens vfsp = rootvfs; 1629fa9e4066Sahrens do { 1630fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1631fa9e4066Sahrens VFS_HOLD(vfsp); 1632fa9e4066Sahrens vfs_found = vfsp; 1633fa9e4066Sahrens break; 1634fa9e4066Sahrens } 1635fa9e4066Sahrens vfsp = vfsp->vfs_next; 1636fa9e4066Sahrens } while (vfsp != rootvfs); 1637fa9e4066Sahrens vfs_list_unlock(); 1638fa9e4066Sahrens return (vfs_found); 1639fa9e4066Sahrens } 1640fa9e4066Sahrens 1641ecd6cf80Smarks /* ARGSUSED */ 1642fa9e4066Sahrens static void 1643ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1644fa9e4066Sahrens { 1645e7437265Sahrens nvlist_t *nvprops = arg; 1646e7437265Sahrens uint64_t version = ZPL_VERSION; 1647e7437265Sahrens 1648e7437265Sahrens (void) nvlist_lookup_uint64(nvprops, 1649e7437265Sahrens zfs_prop_to_name(ZFS_PROP_VERSION), &version); 1650e7437265Sahrens 1651e7437265Sahrens zfs_create_fs(os, cr, version, tx); 1652fa9e4066Sahrens } 1653fa9e4066Sahrens 1654fa9e4066Sahrens static int 1655fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 1656fa9e4066Sahrens { 1657fa9e4066Sahrens objset_t *clone; 1658fa9e4066Sahrens int error = 0; 1659ecd6cf80Smarks nvlist_t *nvprops = NULL; 1660ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 1661fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 1662fa9e4066Sahrens 1663fa9e4066Sahrens switch (type) { 1664fa9e4066Sahrens 1665fa9e4066Sahrens case DMU_OST_ZFS: 1666fa9e4066Sahrens cbfunc = zfs_create_cb; 1667fa9e4066Sahrens break; 1668fa9e4066Sahrens 1669fa9e4066Sahrens case DMU_OST_ZVOL: 1670fa9e4066Sahrens cbfunc = zvol_create_cb; 1671fa9e4066Sahrens break; 1672fa9e4066Sahrens 1673fa9e4066Sahrens default: 16741d452cf5Sahrens cbfunc = NULL; 1675fa9e4066Sahrens } 1676*f18faf3fSek if (strchr(zc->zc_name, '@') || 1677*f18faf3fSek strchr(zc->zc_name, '%')) 16781d452cf5Sahrens return (EINVAL); 1679fa9e4066Sahrens 1680e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 1681990b4856Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1682990b4856Slling &nvprops)) != 0) 1683e9dbad6fSeschrock return (error); 1684e9dbad6fSeschrock 1685e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1686fa9e4066Sahrens /* 1687fa9e4066Sahrens * We're creating a clone of an existing snapshot. 1688fa9e4066Sahrens */ 1689e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1690e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 1691ecd6cf80Smarks nvlist_free(nvprops); 1692fa9e4066Sahrens return (EINVAL); 1693e9dbad6fSeschrock } 1694fa9e4066Sahrens 1695e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 1696fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 1697e9dbad6fSeschrock if (error) { 1698ecd6cf80Smarks nvlist_free(nvprops); 1699fa9e4066Sahrens return (error); 1700e9dbad6fSeschrock } 1701fa9e4066Sahrens error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); 1702fa9e4066Sahrens dmu_objset_close(clone); 1703fa9e4066Sahrens } else { 1704e9dbad6fSeschrock if (cbfunc == NULL) { 1705ecd6cf80Smarks nvlist_free(nvprops); 17061d452cf5Sahrens return (EINVAL); 1707e9dbad6fSeschrock } 17085c5460e9Seschrock 1709e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 1710e9dbad6fSeschrock uint64_t volsize, volblocksize; 1711e9dbad6fSeschrock 1712ecd6cf80Smarks if (nvprops == NULL || 1713ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 1714e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1715e9dbad6fSeschrock &volsize) != 0) { 1716ecd6cf80Smarks nvlist_free(nvprops); 1717e9dbad6fSeschrock return (EINVAL); 1718e9dbad6fSeschrock } 1719e9dbad6fSeschrock 1720ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 1721e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1722e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 1723ecd6cf80Smarks nvlist_free(nvprops); 1724e9dbad6fSeschrock return (EINVAL); 1725e9dbad6fSeschrock } 1726e9dbad6fSeschrock 1727e9dbad6fSeschrock if (error != 0) 1728e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 1729e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 1730e9dbad6fSeschrock 1731e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 1732e9dbad6fSeschrock volblocksize)) != 0 || 1733e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 1734e9dbad6fSeschrock volblocksize)) != 0) { 1735ecd6cf80Smarks nvlist_free(nvprops); 17365c5460e9Seschrock return (error); 1737e9dbad6fSeschrock } 1738e7437265Sahrens } else if (type == DMU_OST_ZFS) { 1739e7437265Sahrens uint64_t version; 1740e7437265Sahrens 1741e7437265Sahrens if (0 == nvlist_lookup_uint64(nvprops, 1742e7437265Sahrens zfs_prop_to_name(ZFS_PROP_VERSION), &version) && 1743e7437265Sahrens (version < ZPL_VERSION_INITIAL || 1744e7437265Sahrens version > ZPL_VERSION)) { 1745e7437265Sahrens nvlist_free(nvprops); 1746e7437265Sahrens return (EINVAL); 1747e7437265Sahrens } 1748fa9e4066Sahrens } 1749e9dbad6fSeschrock 1750e9dbad6fSeschrock error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, 1751ecd6cf80Smarks nvprops); 1752fa9e4066Sahrens } 1753e9dbad6fSeschrock 1754e9dbad6fSeschrock /* 1755e9dbad6fSeschrock * It would be nice to do this atomically. 1756e9dbad6fSeschrock */ 1757e9dbad6fSeschrock if (error == 0) { 175891ebeef5Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 1759e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 1760e9dbad6fSeschrock } 1761e9dbad6fSeschrock 1762ecd6cf80Smarks nvlist_free(nvprops); 1763fa9e4066Sahrens return (error); 1764fa9e4066Sahrens } 1765fa9e4066Sahrens 1766fa9e4066Sahrens static int 17671d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 1768fa9e4066Sahrens { 1769e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 17701d452cf5Sahrens return (EINVAL); 17711d452cf5Sahrens return (dmu_objset_snapshot(zc->zc_name, 1772e9dbad6fSeschrock zc->zc_value, zc->zc_cookie)); 17731d452cf5Sahrens } 1774fa9e4066Sahrens 1775cdf5b4caSmmusante int 17761d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 17771d452cf5Sahrens { 17781d452cf5Sahrens char *snapname = arg; 17791d452cf5Sahrens char *cp; 17800b69c2f0Sahrens vfs_t *vfsp = NULL; 17811d452cf5Sahrens 17821d452cf5Sahrens /* 17831d452cf5Sahrens * Snapshots (which are under .zfs control) must be unmounted 17841d452cf5Sahrens * before they can be destroyed. 17851d452cf5Sahrens */ 17861d452cf5Sahrens 17871d452cf5Sahrens if (snapname) { 17881d452cf5Sahrens (void) strcat(name, "@"); 17891d452cf5Sahrens (void) strcat(name, snapname); 17901d452cf5Sahrens vfsp = zfs_get_vfs(name); 17911d452cf5Sahrens cp = strchr(name, '@'); 17921d452cf5Sahrens *cp = '\0'; 17930b69c2f0Sahrens } else if (strchr(name, '@')) { 17941d452cf5Sahrens vfsp = zfs_get_vfs(name); 17951d452cf5Sahrens } 17961d452cf5Sahrens 17971d452cf5Sahrens if (vfsp) { 1798fa9e4066Sahrens /* 17991d452cf5Sahrens * Always force the unmount for snapshots. 1800fa9e4066Sahrens */ 18011d452cf5Sahrens int flag = MS_FORCE; 18021d452cf5Sahrens int err; 18031d452cf5Sahrens 18041d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 1805fa9e4066Sahrens VFS_RELE(vfsp); 18061d452cf5Sahrens return (err); 1807fa9e4066Sahrens } 18081d452cf5Sahrens VFS_RELE(vfsp); 18091d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 18101d452cf5Sahrens return (err); 18111d452cf5Sahrens } 18121d452cf5Sahrens return (0); 18131d452cf5Sahrens } 18141d452cf5Sahrens 18151d452cf5Sahrens static int 18161d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 18171d452cf5Sahrens { 18181d452cf5Sahrens int err; 18191d452cf5Sahrens 1820e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 18211d452cf5Sahrens return (EINVAL); 18221d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 1823e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 18241d452cf5Sahrens if (err) 18251d452cf5Sahrens return (err); 1826e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 18271d452cf5Sahrens } 18281d452cf5Sahrens 18291d452cf5Sahrens static int 18301d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 18311d452cf5Sahrens { 18321d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 18331d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 18341d452cf5Sahrens if (err) 18351d452cf5Sahrens return (err); 1836fa9e4066Sahrens } 1837fa9e4066Sahrens 1838fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 1839fa9e4066Sahrens } 1840fa9e4066Sahrens 1841fa9e4066Sahrens static int 1842fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 1843fa9e4066Sahrens { 1844fa9e4066Sahrens return (dmu_objset_rollback(zc->zc_name)); 1845fa9e4066Sahrens } 1846fa9e4066Sahrens 1847fa9e4066Sahrens static int 1848fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 1849fa9e4066Sahrens { 18507f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 1851cdf5b4caSmmusante 1852e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1853*f18faf3fSek if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 1854*f18faf3fSek strchr(zc->zc_value, '%')) 1855fa9e4066Sahrens return (EINVAL); 1856fa9e4066Sahrens 1857cdf5b4caSmmusante /* 1858cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 1859cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 1860cdf5b4caSmmusante * to unmount. 1861cdf5b4caSmmusante */ 1862cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 1863fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 18641d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 18651d452cf5Sahrens if (err) 18661d452cf5Sahrens return (err); 1867fa9e4066Sahrens } 1868fa9e4066Sahrens 1869cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 1870fa9e4066Sahrens } 1871fa9e4066Sahrens 1872fa9e4066Sahrens static int 1873fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc) 1874fa9e4066Sahrens { 1875fa9e4066Sahrens file_t *fp; 1876a2eea2e1Sahrens offset_t new_off; 1877*f18faf3fSek objset_t *os; 1878*f18faf3fSek zfsvfs_t *zfsvfs = NULL; 1879*f18faf3fSek char *cp; 1880*f18faf3fSek char cosname[MAXNAMELEN]; 1881*f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 1882*f18faf3fSek int error, fd; 1883fa9e4066Sahrens 18843ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 1885*f18faf3fSek strchr(zc->zc_value, '@') == NULL || 1886*f18faf3fSek strchr(zc->zc_value, '%')) 18873ccfa83cSahrens return (EINVAL); 18883ccfa83cSahrens 1889fa9e4066Sahrens fd = zc->zc_cookie; 1890fa9e4066Sahrens fp = getf(fd); 1891fa9e4066Sahrens if (fp == NULL) 1892fa9e4066Sahrens return (EBADF); 1893*f18faf3fSek 1894*f18faf3fSek /* 1895*f18faf3fSek * Get the zfsvfs for the receiving objset. There 1896*f18faf3fSek * won't be one if we're operating on a zvol, if the 1897*f18faf3fSek * objset doesn't exist yet, or is not mounted. 1898*f18faf3fSek */ 1899*f18faf3fSek cp = strchr(zc->zc_value, '@'); 1900*f18faf3fSek *cp = '\0'; 1901*f18faf3fSek error = dmu_objset_open(zc->zc_value, DMU_OST_ANY, 1902*f18faf3fSek DS_MODE_STANDARD | DS_MODE_READONLY, &os); 1903*f18faf3fSek *cp = '@'; 1904*f18faf3fSek if (!error) { 1905*f18faf3fSek if (dmu_objset_type(os) == DMU_OST_ZFS) { 1906*f18faf3fSek mutex_enter(&os->os->os_user_ptr_lock); 1907*f18faf3fSek zfsvfs = dmu_objset_get_user(os); 1908*f18faf3fSek if (zfsvfs != NULL) 1909*f18faf3fSek VFS_HOLD(zfsvfs->z_vfs); 1910*f18faf3fSek mutex_exit(&os->os->os_user_ptr_lock); 1911*f18faf3fSek } 1912*f18faf3fSek dmu_objset_close(os); 1913*f18faf3fSek } 1914*f18faf3fSek 1915e9dbad6fSeschrock error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record, 1916*f18faf3fSek &zc->zc_cookie, force, zfsvfs != NULL, fp->f_vnode, 1917*f18faf3fSek fp->f_offset, cosname); 1918*f18faf3fSek 1919*f18faf3fSek /* 1920*f18faf3fSek * For incremental snapshots where we created a 1921*f18faf3fSek * temporary clone, we now swap zfsvfs::z_os with 1922*f18faf3fSek * the newly created and received "cosname". 1923*f18faf3fSek */ 1924*f18faf3fSek if (!error && zfsvfs != NULL) { 1925*f18faf3fSek char osname[MAXNAMELEN]; 1926*f18faf3fSek int mode; 1927*f18faf3fSek 1928*f18faf3fSek error = zfs_suspend_fs(zfsvfs, osname, &mode); 1929*f18faf3fSek if (!error) { 1930*f18faf3fSek int swap_err; 1931*f18faf3fSek int snap_err = 0; 1932*f18faf3fSek 1933*f18faf3fSek swap_err = dsl_dataset_clone_swap(cosname, force); 1934*f18faf3fSek if (!swap_err) { 1935*f18faf3fSek char *cp = strrchr(zc->zc_value, '@'); 1936*f18faf3fSek 1937*f18faf3fSek *cp = '\0'; 1938*f18faf3fSek snap_err = dmu_replay_end_snapshot(zc->zc_value, 1939*f18faf3fSek &zc->zc_begin_record); 1940*f18faf3fSek *cp = '@'; 1941*f18faf3fSek } 1942*f18faf3fSek error = zfs_resume_fs(zfsvfs, osname, mode); 1943*f18faf3fSek if (!error) 1944*f18faf3fSek error = swap_err; 1945*f18faf3fSek if (!error) 1946*f18faf3fSek error = snap_err; 1947*f18faf3fSek } 1948a2eea2e1Sahrens 1949*f18faf3fSek /* destroy the clone we created */ 1950*f18faf3fSek (void) dmu_objset_destroy(cosname); 1951*f18faf3fSek } 1952*f18faf3fSek if (zfsvfs != NULL) 1953*f18faf3fSek VFS_RELE(zfsvfs->z_vfs); 1954a2eea2e1Sahrens new_off = fp->f_offset + zc->zc_cookie; 1955a2eea2e1Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0) 1956a2eea2e1Sahrens fp->f_offset = new_off; 1957a2eea2e1Sahrens 1958fa9e4066Sahrens releasef(fd); 1959fa9e4066Sahrens return (error); 1960fa9e4066Sahrens } 1961fa9e4066Sahrens 1962fa9e4066Sahrens static int 1963fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc) 1964fa9e4066Sahrens { 1965fa9e4066Sahrens objset_t *fromsnap = NULL; 1966fa9e4066Sahrens objset_t *tosnap; 1967fa9e4066Sahrens file_t *fp; 1968fa9e4066Sahrens int error; 1969fa9e4066Sahrens 1970fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1971fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); 1972fa9e4066Sahrens if (error) 1973fa9e4066Sahrens return (error); 1974fa9e4066Sahrens 1975e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 1976a2eea2e1Sahrens char buf[MAXPATHLEN]; 1977a2eea2e1Sahrens char *cp; 1978a2eea2e1Sahrens 1979a2eea2e1Sahrens (void) strncpy(buf, zc->zc_name, sizeof (buf)); 1980a2eea2e1Sahrens cp = strchr(buf, '@'); 1981a2eea2e1Sahrens if (cp) 1982a2eea2e1Sahrens *(cp+1) = 0; 1983a2eea2e1Sahrens (void) strncat(buf, zc->zc_value, sizeof (buf)); 1984a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 1985fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); 1986fa9e4066Sahrens if (error) { 1987fa9e4066Sahrens dmu_objset_close(tosnap); 1988fa9e4066Sahrens return (error); 1989fa9e4066Sahrens } 1990fa9e4066Sahrens } 1991fa9e4066Sahrens 1992fa9e4066Sahrens fp = getf(zc->zc_cookie); 1993fa9e4066Sahrens if (fp == NULL) { 1994fa9e4066Sahrens dmu_objset_close(tosnap); 1995fa9e4066Sahrens if (fromsnap) 1996fa9e4066Sahrens dmu_objset_close(fromsnap); 1997fa9e4066Sahrens return (EBADF); 1998fa9e4066Sahrens } 1999fa9e4066Sahrens 2000fa9e4066Sahrens error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode); 2001fa9e4066Sahrens 2002fa9e4066Sahrens releasef(zc->zc_cookie); 2003fa9e4066Sahrens if (fromsnap) 2004fa9e4066Sahrens dmu_objset_close(fromsnap); 2005fa9e4066Sahrens dmu_objset_close(tosnap); 2006fa9e4066Sahrens return (error); 2007fa9e4066Sahrens } 2008fa9e4066Sahrens 2009ea8dc4b6Seschrock static int 2010ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 2011ea8dc4b6Seschrock { 2012ea8dc4b6Seschrock int id, error; 2013ea8dc4b6Seschrock 2014ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2015ea8dc4b6Seschrock &zc->zc_inject_record); 2016ea8dc4b6Seschrock 2017ea8dc4b6Seschrock if (error == 0) 2018ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 2019ea8dc4b6Seschrock 2020ea8dc4b6Seschrock return (error); 2021ea8dc4b6Seschrock } 2022ea8dc4b6Seschrock 2023ea8dc4b6Seschrock static int 2024ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 2025ea8dc4b6Seschrock { 2026ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 2027ea8dc4b6Seschrock } 2028ea8dc4b6Seschrock 2029ea8dc4b6Seschrock static int 2030ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2031ea8dc4b6Seschrock { 2032ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2033ea8dc4b6Seschrock int error; 2034ea8dc4b6Seschrock 2035ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2036ea8dc4b6Seschrock &zc->zc_inject_record); 2037ea8dc4b6Seschrock 2038ea8dc4b6Seschrock zc->zc_guid = id; 2039ea8dc4b6Seschrock 2040ea8dc4b6Seschrock return (error); 2041ea8dc4b6Seschrock } 2042ea8dc4b6Seschrock 2043ea8dc4b6Seschrock static int 2044ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2045ea8dc4b6Seschrock { 2046ea8dc4b6Seschrock spa_t *spa; 2047ea8dc4b6Seschrock int error; 2048e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2049ea8dc4b6Seschrock 2050ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2051ea8dc4b6Seschrock return (error); 2052ea8dc4b6Seschrock 2053e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2054ea8dc4b6Seschrock &count); 2055ea8dc4b6Seschrock if (error == 0) 2056e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2057ea8dc4b6Seschrock else 2058e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2059ea8dc4b6Seschrock 2060ea8dc4b6Seschrock spa_close(spa, FTAG); 2061ea8dc4b6Seschrock 2062ea8dc4b6Seschrock return (error); 2063ea8dc4b6Seschrock } 2064ea8dc4b6Seschrock 2065ea8dc4b6Seschrock static int 2066ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2067ea8dc4b6Seschrock { 2068ea8dc4b6Seschrock spa_t *spa; 2069ea8dc4b6Seschrock vdev_t *vd; 20703d7072f8Seschrock uint64_t txg; 2071bb8b5132Sek int error; 2072ea8dc4b6Seschrock 2073ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2074ea8dc4b6Seschrock return (error); 2075ea8dc4b6Seschrock 20763d7072f8Seschrock txg = spa_vdev_enter(spa); 2077ea8dc4b6Seschrock 2078e9dbad6fSeschrock if (zc->zc_guid == 0) { 2079ea8dc4b6Seschrock vd = NULL; 2080e9dbad6fSeschrock } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { 20813d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, ENODEV); 2082ea8dc4b6Seschrock spa_close(spa, FTAG); 2083ea8dc4b6Seschrock return (ENODEV); 2084ea8dc4b6Seschrock } 2085ea8dc4b6Seschrock 2086ea8dc4b6Seschrock vdev_clear(spa, vd); 2087ea8dc4b6Seschrock 20883d7072f8Seschrock (void) spa_vdev_exit(spa, NULL, txg, 0); 2089ea8dc4b6Seschrock 2090ea8dc4b6Seschrock spa_close(spa, FTAG); 2091ea8dc4b6Seschrock 2092ea8dc4b6Seschrock return (0); 2093ea8dc4b6Seschrock } 2094ea8dc4b6Seschrock 209599653d4eSeschrock static int 209699653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 209799653d4eSeschrock { 20980b69c2f0Sahrens char *cp; 20990b69c2f0Sahrens 21000b69c2f0Sahrens /* 21010b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 21020b69c2f0Sahrens * it's easier. 21030b69c2f0Sahrens */ 2104e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 21050b69c2f0Sahrens if (cp) 21060b69c2f0Sahrens *cp = '\0'; 2107e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 21080b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 210999653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 211099653d4eSeschrock } 211199653d4eSeschrock 2112ecd6cf80Smarks /* 2113ecd6cf80Smarks * We don't want to have a hard dependency 2114ecd6cf80Smarks * against some special symbols in sharefs 2115ecd6cf80Smarks * and nfs. Determine them if needed when 2116ecd6cf80Smarks * the first file system is shared. 2117ecd6cf80Smarks * Neither sharefs or nfs are unloadable modules. 2118ecd6cf80Smarks */ 2119ecd6cf80Smarks int (*zexport_fs)(void *arg); 2120ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2121ecd6cf80Smarks 2122ecd6cf80Smarks int zfs_share_inited; 2123ecd6cf80Smarks ddi_modhandle_t nfs_mod; 2124ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 2125ecd6cf80Smarks kmutex_t zfs_share_lock; 2126ecd6cf80Smarks 2127ecd6cf80Smarks static int 2128ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 2129ecd6cf80Smarks { 2130ecd6cf80Smarks int error; 2131ecd6cf80Smarks int opcode; 2132ecd6cf80Smarks 2133ecd6cf80Smarks if (zfs_share_inited == 0) { 2134ecd6cf80Smarks mutex_enter(&zfs_share_lock); 2135ecd6cf80Smarks nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error); 2136ecd6cf80Smarks sharefs_mod = ddi_modopen("fs/sharefs", 2137ecd6cf80Smarks KRTLD_MODE_FIRST, &error); 2138ecd6cf80Smarks if (nfs_mod == NULL || sharefs_mod == NULL) { 2139ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2140ecd6cf80Smarks return (ENOSYS); 2141ecd6cf80Smarks } 2142ecd6cf80Smarks if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *)) 2143ecd6cf80Smarks ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) { 2144ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2145ecd6cf80Smarks return (ENOSYS); 2146ecd6cf80Smarks } 2147ecd6cf80Smarks 2148ecd6cf80Smarks if (zshare_fs == NULL && ((zshare_fs = 2149ecd6cf80Smarks (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2150ecd6cf80Smarks ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2151ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2152ecd6cf80Smarks return (ENOSYS); 2153ecd6cf80Smarks } 2154ecd6cf80Smarks zfs_share_inited = 1; 2155ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2156ecd6cf80Smarks } 2157ecd6cf80Smarks 2158ecd6cf80Smarks if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata)) 2159ecd6cf80Smarks return (error); 2160ecd6cf80Smarks 2161ecd6cf80Smarks opcode = (zc->zc_share.z_sharetype == B_TRUE) ? 2162ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 2163ecd6cf80Smarks 2164ecd6cf80Smarks error = zshare_fs(opcode, 2165ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 2166ecd6cf80Smarks zc->zc_share.z_sharemax); 2167ecd6cf80Smarks 2168ecd6cf80Smarks return (error); 2169ecd6cf80Smarks 2170ecd6cf80Smarks } 2171ecd6cf80Smarks 2172ecd6cf80Smarks /* 21732a6b87f0Sek * pool create, destroy, and export don't log the history as part of 21742a6b87f0Sek * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 21752a6b87f0Sek * do the logging of those commands. 2176ecd6cf80Smarks */ 2177fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 2178228975ccSek { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2179e7437265Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2180e7437265Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2181e7437265Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2182e7437265Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 2183e7437265Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2184e7437265Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2185e7437265Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2186e7437265Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2187e7437265Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2188e7437265Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2189e7437265Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2190e7437265Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2191e7437265Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2192e7437265Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2193e7437265Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2194e7437265Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2195e7437265Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2196bd00f61bSrm { zfs_ioc_objset_version, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2197ecd6cf80Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 2198e7437265Sahrens DATASET_NAME, B_FALSE }, 2199ecd6cf80Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 2200e7437265Sahrens DATASET_NAME, B_FALSE }, 2201e7437265Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 2202e7437265Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2203e7437265Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2204e7437265Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 2205e7437265Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2206e7437265Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 2207e7437265Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 2208e7437265Sahrens { zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 2209e7437265Sahrens { zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 2210e7437265Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2211e7437265Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2212e7437265Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2213e7437265Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 2214e7437265Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2215e7437265Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 2216e7437265Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2217e7437265Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 2218e7437265Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2219e7437265Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2220e7437265Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2221e7437265Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2222e7437265Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 2223e7437265Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2224ecd6cf80Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 2225e7437265Sahrens DATASET_NAME, B_FALSE }, 2226e45ce728Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 2227e45ce728Sahrens { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 2228fa9e4066Sahrens }; 2229fa9e4066Sahrens 2230fa9e4066Sahrens static int 2231fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 2232fa9e4066Sahrens { 2233fa9e4066Sahrens zfs_cmd_t *zc; 2234fa9e4066Sahrens uint_t vec; 22351d452cf5Sahrens int error, rc; 2236fa9e4066Sahrens 2237fa9e4066Sahrens if (getminor(dev) != 0) 2238fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 2239fa9e4066Sahrens 2240fa9e4066Sahrens vec = cmd - ZFS_IOC; 224191ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 2242fa9e4066Sahrens 2243fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 2244fa9e4066Sahrens return (EINVAL); 2245fa9e4066Sahrens 2246fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2247fa9e4066Sahrens 2248fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 2249fa9e4066Sahrens 225091ebeef5Sahrens if (error == 0) 2251ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 2252fa9e4066Sahrens 2253fa9e4066Sahrens /* 2254fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 2255fa9e4066Sahrens * the lower layers. 2256fa9e4066Sahrens */ 2257fa9e4066Sahrens if (error == 0) { 2258fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 2259fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 2260e7437265Sahrens case POOL_NAME: 2261fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 2262fa9e4066Sahrens error = EINVAL; 2263fa9e4066Sahrens break; 2264fa9e4066Sahrens 2265e7437265Sahrens case DATASET_NAME: 2266fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 2267fa9e4066Sahrens error = EINVAL; 2268fa9e4066Sahrens break; 22695ad82045Snd 2270e7437265Sahrens case NO_NAME: 22715ad82045Snd break; 2272fa9e4066Sahrens } 2273fa9e4066Sahrens } 2274fa9e4066Sahrens 2275fa9e4066Sahrens if (error == 0) 2276fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 2277fa9e4066Sahrens 22781d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 2279ecd6cf80Smarks if (error == 0) { 22801d452cf5Sahrens error = rc; 2281ecd6cf80Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 2282ecd6cf80Smarks zfs_log_history(zc); 2283ecd6cf80Smarks } 2284fa9e4066Sahrens 2285fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 2286fa9e4066Sahrens return (error); 2287fa9e4066Sahrens } 2288fa9e4066Sahrens 2289fa9e4066Sahrens static int 2290fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2291fa9e4066Sahrens { 2292fa9e4066Sahrens if (cmd != DDI_ATTACH) 2293fa9e4066Sahrens return (DDI_FAILURE); 2294fa9e4066Sahrens 2295fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 2296fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 2297fa9e4066Sahrens return (DDI_FAILURE); 2298fa9e4066Sahrens 2299fa9e4066Sahrens zfs_dip = dip; 2300fa9e4066Sahrens 2301fa9e4066Sahrens ddi_report_dev(dip); 2302fa9e4066Sahrens 2303fa9e4066Sahrens return (DDI_SUCCESS); 2304fa9e4066Sahrens } 2305fa9e4066Sahrens 2306fa9e4066Sahrens static int 2307fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2308fa9e4066Sahrens { 2309fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 2310fa9e4066Sahrens return (DDI_FAILURE); 2311fa9e4066Sahrens 2312fa9e4066Sahrens if (cmd != DDI_DETACH) 2313fa9e4066Sahrens return (DDI_FAILURE); 2314fa9e4066Sahrens 2315fa9e4066Sahrens zfs_dip = NULL; 2316fa9e4066Sahrens 2317fa9e4066Sahrens ddi_prop_remove_all(dip); 2318fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 2319fa9e4066Sahrens 2320fa9e4066Sahrens return (DDI_SUCCESS); 2321fa9e4066Sahrens } 2322fa9e4066Sahrens 2323fa9e4066Sahrens /*ARGSUSED*/ 2324fa9e4066Sahrens static int 2325fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2326fa9e4066Sahrens { 2327fa9e4066Sahrens switch (infocmd) { 2328fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 2329fa9e4066Sahrens *result = zfs_dip; 2330fa9e4066Sahrens return (DDI_SUCCESS); 2331fa9e4066Sahrens 2332fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 2333a0965f35Sbonwick *result = (void *)0; 2334fa9e4066Sahrens return (DDI_SUCCESS); 2335fa9e4066Sahrens } 2336fa9e4066Sahrens 2337fa9e4066Sahrens return (DDI_FAILURE); 2338fa9e4066Sahrens } 2339fa9e4066Sahrens 2340fa9e4066Sahrens /* 2341fa9e4066Sahrens * OK, so this is a little weird. 2342fa9e4066Sahrens * 2343fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 2344fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 2345fa9e4066Sahrens * 2346fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 2347fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 2348fa9e4066Sahrens */ 2349fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 2350fa9e4066Sahrens zvol_open, /* open */ 2351fa9e4066Sahrens zvol_close, /* close */ 2352fa9e4066Sahrens zvol_strategy, /* strategy */ 2353fa9e4066Sahrens nodev, /* print */ 2354fa9e4066Sahrens nodev, /* dump */ 2355fa9e4066Sahrens zvol_read, /* read */ 2356fa9e4066Sahrens zvol_write, /* write */ 2357fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 2358fa9e4066Sahrens nodev, /* devmap */ 2359fa9e4066Sahrens nodev, /* mmap */ 2360fa9e4066Sahrens nodev, /* segmap */ 2361fa9e4066Sahrens nochpoll, /* poll */ 2362fa9e4066Sahrens ddi_prop_op, /* prop_op */ 2363fa9e4066Sahrens NULL, /* streamtab */ 2364fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 2365fa9e4066Sahrens CB_REV, /* version */ 2366feb08c6bSbillm nodev, /* async read */ 2367feb08c6bSbillm nodev, /* async write */ 2368fa9e4066Sahrens }; 2369fa9e4066Sahrens 2370fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 2371fa9e4066Sahrens DEVO_REV, /* version */ 2372fa9e4066Sahrens 0, /* refcnt */ 2373fa9e4066Sahrens zfs_info, /* info */ 2374fa9e4066Sahrens nulldev, /* identify */ 2375fa9e4066Sahrens nulldev, /* probe */ 2376fa9e4066Sahrens zfs_attach, /* attach */ 2377fa9e4066Sahrens zfs_detach, /* detach */ 2378fa9e4066Sahrens nodev, /* reset */ 2379fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 2380fa9e4066Sahrens NULL /* no bus operations */ 2381fa9e4066Sahrens }; 2382fa9e4066Sahrens 2383fa9e4066Sahrens static struct modldrv zfs_modldrv = { 2384e7437265Sahrens &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, 2385e9dbad6fSeschrock &zfs_dev_ops 2386fa9e4066Sahrens }; 2387fa9e4066Sahrens 2388fa9e4066Sahrens static struct modlinkage modlinkage = { 2389fa9e4066Sahrens MODREV_1, 2390fa9e4066Sahrens (void *)&zfs_modlfs, 2391fa9e4066Sahrens (void *)&zfs_modldrv, 2392fa9e4066Sahrens NULL 2393fa9e4066Sahrens }; 2394fa9e4066Sahrens 2395ec533521Sfr 2396ec533521Sfr uint_t zfs_fsyncer_key; 2397*f18faf3fSek extern uint_t rrw_tsd_key; 2398ec533521Sfr 2399fa9e4066Sahrens int 2400fa9e4066Sahrens _init(void) 2401fa9e4066Sahrens { 2402fa9e4066Sahrens int error; 2403fa9e4066Sahrens 2404a0965f35Sbonwick spa_init(FREAD | FWRITE); 2405a0965f35Sbonwick zfs_init(); 2406a0965f35Sbonwick zvol_init(); 2407a0965f35Sbonwick 2408a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 2409a0965f35Sbonwick zvol_fini(); 2410a0965f35Sbonwick zfs_fini(); 2411a0965f35Sbonwick spa_fini(); 2412fa9e4066Sahrens return (error); 2413a0965f35Sbonwick } 2414fa9e4066Sahrens 2415ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 2416*f18faf3fSek tsd_create(&rrw_tsd_key, NULL); 2417ec533521Sfr 2418fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 2419fa9e4066Sahrens ASSERT(error == 0); 2420ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 2421fa9e4066Sahrens 2422fa9e4066Sahrens return (0); 2423fa9e4066Sahrens } 2424fa9e4066Sahrens 2425fa9e4066Sahrens int 2426fa9e4066Sahrens _fini(void) 2427fa9e4066Sahrens { 2428fa9e4066Sahrens int error; 2429fa9e4066Sahrens 2430ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 2431fa9e4066Sahrens return (EBUSY); 2432fa9e4066Sahrens 2433fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 2434fa9e4066Sahrens return (error); 2435fa9e4066Sahrens 2436fa9e4066Sahrens zvol_fini(); 2437fa9e4066Sahrens zfs_fini(); 2438fa9e4066Sahrens spa_fini(); 2439ecd6cf80Smarks if (zfs_share_inited) { 2440ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 2441ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 2442ecd6cf80Smarks } 2443fa9e4066Sahrens 2444ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 2445fa9e4066Sahrens ldi_ident_release(zfs_li); 2446fa9e4066Sahrens zfs_li = NULL; 2447ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 2448fa9e4066Sahrens 2449fa9e4066Sahrens return (error); 2450fa9e4066Sahrens } 2451fa9e4066Sahrens 2452fa9e4066Sahrens int 2453fa9e4066Sahrens _info(struct modinfo *modinfop) 2454fa9e4066Sahrens { 2455fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 2456fa9e4066Sahrens } 2457