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 /* 22379c004dSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/types.h> 27fa9e4066Sahrens #include <sys/param.h> 28fa9e4066Sahrens #include <sys/errno.h> 29fa9e4066Sahrens #include <sys/uio.h> 30fa9e4066Sahrens #include <sys/buf.h> 31fa9e4066Sahrens #include <sys/modctl.h> 32fa9e4066Sahrens #include <sys/open.h> 33fa9e4066Sahrens #include <sys/file.h> 34fa9e4066Sahrens #include <sys/kmem.h> 35fa9e4066Sahrens #include <sys/conf.h> 36fa9e4066Sahrens #include <sys/cmn_err.h> 37fa9e4066Sahrens #include <sys/stat.h> 38fa9e4066Sahrens #include <sys/zfs_ioctl.h> 39da6c28aaSamw #include <sys/zfs_znode.h> 40fa9e4066Sahrens #include <sys/zap.h> 41fa9e4066Sahrens #include <sys/spa.h> 42b1b8ab34Slling #include <sys/spa_impl.h> 43fa9e4066Sahrens #include <sys/vdev.h> 44fa9e4066Sahrens #include <sys/dmu.h> 45fa9e4066Sahrens #include <sys/dsl_dir.h> 46fa9e4066Sahrens #include <sys/dsl_dataset.h> 47fa9e4066Sahrens #include <sys/dsl_prop.h> 48ecd6cf80Smarks #include <sys/dsl_deleg.h> 49ecd6cf80Smarks #include <sys/dmu_objset.h> 50fa9e4066Sahrens #include <sys/ddi.h> 51fa9e4066Sahrens #include <sys/sunddi.h> 52fa9e4066Sahrens #include <sys/sunldi.h> 53fa9e4066Sahrens #include <sys/policy.h> 54fa9e4066Sahrens #include <sys/zone.h> 55fa9e4066Sahrens #include <sys/nvpair.h> 56fa9e4066Sahrens #include <sys/pathname.h> 57fa9e4066Sahrens #include <sys/mount.h> 58fa9e4066Sahrens #include <sys/sdt.h> 59fa9e4066Sahrens #include <sys/fs/zfs.h> 60fa9e4066Sahrens #include <sys/zfs_ctldir.h> 61da6c28aaSamw #include <sys/zfs_dir.h> 62a2eea2e1Sahrens #include <sys/zvol.h> 63ecd6cf80Smarks #include <sharefs/share.h> 64f18faf3fSek #include <sys/dmu_objset.h> 65fa9e4066Sahrens 66fa9e4066Sahrens #include "zfs_namecheck.h" 67e9dbad6fSeschrock #include "zfs_prop.h" 68ecd6cf80Smarks #include "zfs_deleg.h" 69fa9e4066Sahrens 70fa9e4066Sahrens extern struct modlfs zfs_modlfs; 71fa9e4066Sahrens 72fa9e4066Sahrens extern void zfs_init(void); 73fa9e4066Sahrens extern void zfs_fini(void); 74fa9e4066Sahrens 75fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 76fa9e4066Sahrens dev_info_t *zfs_dip; 77fa9e4066Sahrens 78fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 79ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 80fa9e4066Sahrens 8154d692b7SGeorge Wilson typedef enum { 8254d692b7SGeorge Wilson NO_NAME, 8354d692b7SGeorge Wilson POOL_NAME, 8454d692b7SGeorge Wilson DATASET_NAME 8554d692b7SGeorge Wilson } zfs_ioc_namecheck_t; 8654d692b7SGeorge Wilson 87fa9e4066Sahrens typedef struct zfs_ioc_vec { 88fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 89fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 9054d692b7SGeorge Wilson zfs_ioc_namecheck_t zvec_namecheck; 91ecd6cf80Smarks boolean_t zvec_his_log; 9254d692b7SGeorge Wilson boolean_t zvec_pool_check; 93fa9e4066Sahrens } zfs_ioc_vec_t; 94fa9e4066Sahrens 9514843421SMatthew Ahrens /* This array is indexed by zfs_userquota_prop_t */ 9614843421SMatthew Ahrens static const char *userquota_perms[] = { 9714843421SMatthew Ahrens ZFS_DELEG_PERM_USERUSED, 9814843421SMatthew Ahrens ZFS_DELEG_PERM_USERQUOTA, 9914843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPUSED, 10014843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPQUOTA, 10114843421SMatthew Ahrens }; 10214843421SMatthew Ahrens 10314843421SMatthew Ahrens static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 1046e77af0aSDavid Pacheco static void clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops); 1050a48a24eStimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 1060a48a24eStimh boolean_t *); 1070a48a24eStimh int zfs_set_prop_nvlist(const char *, nvlist_t *); 1080a48a24eStimh 109fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 110fa9e4066Sahrens void 111fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 112fa9e4066Sahrens { 113fa9e4066Sahrens const char *newfile; 114fa9e4066Sahrens char buf[256]; 115fa9e4066Sahrens va_list adx; 116fa9e4066Sahrens 117fa9e4066Sahrens /* 118fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 119fa9e4066Sahrens */ 120fa9e4066Sahrens newfile = strrchr(file, '/'); 121fa9e4066Sahrens if (newfile != NULL) { 122fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 123fa9e4066Sahrens } else { 124fa9e4066Sahrens newfile = file; 125fa9e4066Sahrens } 126fa9e4066Sahrens 127fa9e4066Sahrens va_start(adx, fmt); 128fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 129fa9e4066Sahrens va_end(adx); 130fa9e4066Sahrens 131fa9e4066Sahrens /* 132fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 133fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 134fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 135fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 136fa9e4066Sahrens * arg0 = file name 137fa9e4066Sahrens * arg1 = function name 138fa9e4066Sahrens * arg2 = line number 139fa9e4066Sahrens * arg3 = message 140fa9e4066Sahrens */ 141fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 142fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 143fa9e4066Sahrens } 144fa9e4066Sahrens 145ecd6cf80Smarks static void 146228975ccSek history_str_free(char *buf) 147228975ccSek { 148228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 149228975ccSek } 150228975ccSek 151228975ccSek static char * 152228975ccSek history_str_get(zfs_cmd_t *zc) 153ecd6cf80Smarks { 15440feaa91Sahrens char *buf; 155ecd6cf80Smarks 156ecd6cf80Smarks if (zc->zc_history == NULL) 157228975ccSek return (NULL); 158e7437265Sahrens 159ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 160ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 161ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 162228975ccSek history_str_free(buf); 163228975ccSek return (NULL); 164ecd6cf80Smarks } 165ecd6cf80Smarks 166ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 167ecd6cf80Smarks 168228975ccSek return (buf); 169228975ccSek } 170ecd6cf80Smarks 17115e6edf1Sgw /* 17215e6edf1Sgw * Check to see if the named dataset is currently defined as bootable 17315e6edf1Sgw */ 17415e6edf1Sgw static boolean_t 17515e6edf1Sgw zfs_is_bootfs(const char *name) 17615e6edf1Sgw { 177503ad85cSMatthew Ahrens objset_t *os; 17815e6edf1Sgw 179503ad85cSMatthew Ahrens if (dmu_objset_hold(name, FTAG, &os) == 0) { 180503ad85cSMatthew Ahrens boolean_t ret; 181*b24ab676SJeff Bonwick ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os))); 182503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 183503ad85cSMatthew Ahrens return (ret); 18415e6edf1Sgw } 185503ad85cSMatthew Ahrens return (B_FALSE); 18615e6edf1Sgw } 18715e6edf1Sgw 188c2a93d44Stimh /* 1890a48a24eStimh * zfs_earlier_version 190c2a93d44Stimh * 191c2a93d44Stimh * Return non-zero if the spa version is less than requested version. 192c2a93d44Stimh */ 193da6c28aaSamw static int 1940a48a24eStimh zfs_earlier_version(const char *name, int version) 195da6c28aaSamw { 196da6c28aaSamw spa_t *spa; 197da6c28aaSamw 198da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 199da6c28aaSamw if (spa_version(spa) < version) { 200da6c28aaSamw spa_close(spa, FTAG); 201da6c28aaSamw return (1); 202da6c28aaSamw } 203da6c28aaSamw spa_close(spa, FTAG); 204da6c28aaSamw } 205da6c28aaSamw return (0); 206da6c28aaSamw } 207da6c28aaSamw 2089e6eda55Smarks /* 209745cd3c5Smaybee * zpl_earlier_version 2109e6eda55Smarks * 211745cd3c5Smaybee * Return TRUE if the ZPL version is less than requested version. 2129e6eda55Smarks */ 213745cd3c5Smaybee static boolean_t 214745cd3c5Smaybee zpl_earlier_version(const char *name, int version) 2159e6eda55Smarks { 2169e6eda55Smarks objset_t *os; 217745cd3c5Smaybee boolean_t rc = B_TRUE; 2189e6eda55Smarks 219503ad85cSMatthew Ahrens if (dmu_objset_hold(name, FTAG, &os) == 0) { 220745cd3c5Smaybee uint64_t zplversion; 2219e6eda55Smarks 222503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 223503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 224503ad85cSMatthew Ahrens return (B_TRUE); 225503ad85cSMatthew Ahrens } 226503ad85cSMatthew Ahrens /* XXX reading from non-owned objset */ 227745cd3c5Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 228745cd3c5Smaybee rc = zplversion < version; 229503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2309e6eda55Smarks } 2319e6eda55Smarks return (rc); 2329e6eda55Smarks } 2339e6eda55Smarks 234228975ccSek static void 235228975ccSek zfs_log_history(zfs_cmd_t *zc) 236228975ccSek { 237228975ccSek spa_t *spa; 238228975ccSek char *buf; 239ecd6cf80Smarks 240228975ccSek if ((buf = history_str_get(zc)) == NULL) 241228975ccSek return; 242228975ccSek 243228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 244228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 245228975ccSek (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 246228975ccSek spa_close(spa, FTAG); 247228975ccSek } 248228975ccSek history_str_free(buf); 249ecd6cf80Smarks } 250ecd6cf80Smarks 251fa9e4066Sahrens /* 252fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 253fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 254fa9e4066Sahrens */ 255fa9e4066Sahrens /* ARGSUSED */ 256fa9e4066Sahrens static int 257ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 258fa9e4066Sahrens { 259fa9e4066Sahrens return (0); 260fa9e4066Sahrens } 261fa9e4066Sahrens 262fa9e4066Sahrens /* 263fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 264fa9e4066Sahrens * no privileges, but must be visible in the local zone. 265fa9e4066Sahrens */ 266fa9e4066Sahrens /* ARGSUSED */ 267fa9e4066Sahrens static int 268ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 269fa9e4066Sahrens { 270fa9e4066Sahrens if (INGLOBALZONE(curproc) || 271ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 272fa9e4066Sahrens return (0); 273fa9e4066Sahrens 274fa9e4066Sahrens return (ENOENT); 275fa9e4066Sahrens } 276fa9e4066Sahrens 277fa9e4066Sahrens static int 278fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 279fa9e4066Sahrens { 280fa9e4066Sahrens uint64_t zoned; 281fa9e4066Sahrens int writable = 1; 282fa9e4066Sahrens 283fa9e4066Sahrens /* 284fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 285fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 286fa9e4066Sahrens */ 287fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 288fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 289fa9e4066Sahrens return (ENOENT); 290fa9e4066Sahrens 291fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 292fa9e4066Sahrens return (ENOENT); 293fa9e4066Sahrens 294fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 295fa9e4066Sahrens /* 296fa9e4066Sahrens * If the fs is zoned, only root can access it from the 297fa9e4066Sahrens * global zone. 298fa9e4066Sahrens */ 299fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 300fa9e4066Sahrens return (EPERM); 301fa9e4066Sahrens } else { 302fa9e4066Sahrens /* 303fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 304fa9e4066Sahrens */ 305fa9e4066Sahrens if (!zoned) 306fa9e4066Sahrens return (EPERM); 307fa9e4066Sahrens 308fa9e4066Sahrens /* must be writable by this zone */ 309fa9e4066Sahrens if (!writable) 310fa9e4066Sahrens return (EPERM); 311fa9e4066Sahrens } 312fa9e4066Sahrens return (0); 313fa9e4066Sahrens } 314fa9e4066Sahrens 315fa9e4066Sahrens int 316ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 317fa9e4066Sahrens { 318fa9e4066Sahrens int error; 319fa9e4066Sahrens 320ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 321ecd6cf80Smarks if (error == 0) { 322ecd6cf80Smarks error = secpolicy_zfs(cr); 323db870a07Sahrens if (error) 324ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 325ecd6cf80Smarks } 326ecd6cf80Smarks return (error); 327ecd6cf80Smarks } 328ecd6cf80Smarks 329ecd6cf80Smarks static int 330ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 331ecd6cf80Smarks { 332ecd6cf80Smarks /* 333ecd6cf80Smarks * Check permissions for special properties. 334ecd6cf80Smarks */ 335ecd6cf80Smarks switch (prop) { 336ecd6cf80Smarks case ZFS_PROP_ZONED: 337ecd6cf80Smarks /* 338ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 339ecd6cf80Smarks */ 340ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 341ecd6cf80Smarks return (EPERM); 342ecd6cf80Smarks break; 343ecd6cf80Smarks 344ecd6cf80Smarks case ZFS_PROP_QUOTA: 345ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 346ecd6cf80Smarks uint64_t zoned; 347ecd6cf80Smarks char setpoint[MAXNAMELEN]; 348ecd6cf80Smarks /* 349ecd6cf80Smarks * Unprivileged users are allowed to modify the 350ecd6cf80Smarks * quota on things *under* (ie. contained by) 351ecd6cf80Smarks * the thing they own. 352ecd6cf80Smarks */ 353ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 354ecd6cf80Smarks setpoint)) 355ecd6cf80Smarks return (EPERM); 356db870a07Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 357ecd6cf80Smarks return (EPERM); 358ecd6cf80Smarks } 359db870a07Sahrens break; 360ecd6cf80Smarks } 361ecd6cf80Smarks 36291ebeef5Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 363ecd6cf80Smarks } 364ecd6cf80Smarks 365ecd6cf80Smarks int 366ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 367ecd6cf80Smarks { 368ecd6cf80Smarks int error; 369ecd6cf80Smarks 370ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 371ecd6cf80Smarks if (error) 372fa9e4066Sahrens return (error); 373fa9e4066Sahrens 374ecd6cf80Smarks /* 375ecd6cf80Smarks * permission to set permissions will be evaluated later in 376ecd6cf80Smarks * dsl_deleg_can_allow() 377ecd6cf80Smarks */ 378ecd6cf80Smarks return (0); 379ecd6cf80Smarks } 380ecd6cf80Smarks 381ecd6cf80Smarks int 382ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 383ecd6cf80Smarks { 384681d9761SEric Taylor return (zfs_secpolicy_write_perms(zc->zc_name, 385681d9761SEric Taylor ZFS_DELEG_PERM_ROLLBACK, cr)); 386ecd6cf80Smarks } 387ecd6cf80Smarks 388ecd6cf80Smarks int 389ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 390ecd6cf80Smarks { 391ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 392ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 393ecd6cf80Smarks } 394ecd6cf80Smarks 395743a77edSAlan Wright static int 396743a77edSAlan Wright zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) 397743a77edSAlan Wright { 398743a77edSAlan Wright vnode_t *vp; 399743a77edSAlan Wright int error; 400743a77edSAlan Wright 401743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 402743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 403743a77edSAlan Wright return (error); 404743a77edSAlan Wright 405743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 406743a77edSAlan Wright 407743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 408743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 409743a77edSAlan Wright zc->zc_name) != 0)) { 410743a77edSAlan Wright VN_RELE(vp); 411743a77edSAlan Wright return (EPERM); 412743a77edSAlan Wright } 413743a77edSAlan Wright 414743a77edSAlan Wright VN_RELE(vp); 415743a77edSAlan Wright return (dsl_deleg_access(zc->zc_name, 416743a77edSAlan Wright ZFS_DELEG_PERM_SHARE, cr)); 417743a77edSAlan Wright } 418743a77edSAlan Wright 419ecd6cf80Smarks int 420ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 421ecd6cf80Smarks { 422ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 423ecd6cf80Smarks return (EPERM); 424ecd6cf80Smarks 4253cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 426ecd6cf80Smarks return (0); 427ecd6cf80Smarks } else { 428743a77edSAlan Wright return (zfs_secpolicy_deleg_share(zc, cr)); 429743a77edSAlan Wright } 430743a77edSAlan Wright } 431ecd6cf80Smarks 432743a77edSAlan Wright int 433743a77edSAlan Wright zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) 434743a77edSAlan Wright { 435743a77edSAlan Wright if (!INGLOBALZONE(curproc)) 436743a77edSAlan Wright return (EPERM); 437ecd6cf80Smarks 438743a77edSAlan Wright if (secpolicy_smb(cr) == 0) { 439743a77edSAlan Wright return (0); 440743a77edSAlan Wright } else { 441743a77edSAlan Wright return (zfs_secpolicy_deleg_share(zc, cr)); 442ecd6cf80Smarks } 443fa9e4066Sahrens } 444fa9e4066Sahrens 445fa9e4066Sahrens static int 446ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 447fa9e4066Sahrens { 448fa9e4066Sahrens char *cp; 449fa9e4066Sahrens 450fa9e4066Sahrens /* 451fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 452fa9e4066Sahrens */ 453ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 454ecd6cf80Smarks cp = strrchr(parent, '@'); 455fa9e4066Sahrens if (cp != NULL) { 456fa9e4066Sahrens cp[0] = '\0'; 457fa9e4066Sahrens } else { 458ecd6cf80Smarks cp = strrchr(parent, '/'); 459fa9e4066Sahrens if (cp == NULL) 460fa9e4066Sahrens return (ENOENT); 461fa9e4066Sahrens cp[0] = '\0'; 462ecd6cf80Smarks } 463ecd6cf80Smarks 464ecd6cf80Smarks return (0); 465ecd6cf80Smarks } 466ecd6cf80Smarks 467ecd6cf80Smarks int 468ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 469ecd6cf80Smarks { 470ecd6cf80Smarks int error; 471ecd6cf80Smarks 472ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 473ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 474ecd6cf80Smarks return (error); 475ecd6cf80Smarks 476ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 477ecd6cf80Smarks } 478ecd6cf80Smarks 479ecd6cf80Smarks static int 480ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 481ecd6cf80Smarks { 482ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 483ecd6cf80Smarks } 484ecd6cf80Smarks 485ecd6cf80Smarks /* 486ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 487ecd6cf80Smarks */ 488ecd6cf80Smarks /* ARGSUSED */ 489ecd6cf80Smarks static int 490ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 491ecd6cf80Smarks { 492ecd6cf80Smarks return (secpolicy_zfs(cr)); 493ecd6cf80Smarks } 494ecd6cf80Smarks 495ecd6cf80Smarks int 496ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 497ecd6cf80Smarks { 498ecd6cf80Smarks char parentname[MAXNAMELEN]; 499ecd6cf80Smarks int error; 500ecd6cf80Smarks 501ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 502ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 503ecd6cf80Smarks return (error); 504ecd6cf80Smarks 505ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 506ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 507ecd6cf80Smarks return (error); 508ecd6cf80Smarks 509ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 510ecd6cf80Smarks sizeof (parentname))) != 0) 511ecd6cf80Smarks return (error); 512ecd6cf80Smarks 513ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 514ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 515ecd6cf80Smarks return (error); 516ecd6cf80Smarks 517ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 518ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 519ecd6cf80Smarks return (error); 520ecd6cf80Smarks 521ecd6cf80Smarks return (error); 522ecd6cf80Smarks } 523ecd6cf80Smarks 524ecd6cf80Smarks static int 525ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 526ecd6cf80Smarks { 527ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 528ecd6cf80Smarks } 529ecd6cf80Smarks 530ecd6cf80Smarks static int 531ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 532ecd6cf80Smarks { 533ecd6cf80Smarks char parentname[MAXNAMELEN]; 534ecd6cf80Smarks objset_t *clone; 535ecd6cf80Smarks int error; 536ecd6cf80Smarks 537ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 538ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 539ecd6cf80Smarks if (error) 540ecd6cf80Smarks return (error); 541ecd6cf80Smarks 542503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &clone); 543ecd6cf80Smarks 544ecd6cf80Smarks if (error == 0) { 545ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 546ecd6cf80Smarks dsl_dir_t *dd; 547503ad85cSMatthew Ahrens dd = clone->os_dsl_dataset->ds_dir; 548ecd6cf80Smarks 549ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 550745cd3c5Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 551745cd3c5Smaybee dd->dd_phys->dd_origin_obj, FTAG, &pclone); 552ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 553ecd6cf80Smarks if (error) { 554503ad85cSMatthew Ahrens dmu_objset_rele(clone, FTAG); 555ecd6cf80Smarks return (error); 556ecd6cf80Smarks } 557ecd6cf80Smarks 558ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 559ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 560ecd6cf80Smarks 561ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 562503ad85cSMatthew Ahrens dmu_objset_rele(clone, FTAG); 563745cd3c5Smaybee dsl_dataset_rele(pclone, FTAG); 564ecd6cf80Smarks if (error == 0) 565ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 566ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 567ecd6cf80Smarks } 568ecd6cf80Smarks return (error); 569ecd6cf80Smarks } 570ecd6cf80Smarks 571ecd6cf80Smarks static int 572ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 573ecd6cf80Smarks { 574ecd6cf80Smarks int error; 575ecd6cf80Smarks 576ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 577ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 578ecd6cf80Smarks return (error); 579ecd6cf80Smarks 580ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 581ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 582ecd6cf80Smarks return (error); 583ecd6cf80Smarks 584ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 585ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 586ecd6cf80Smarks } 587ecd6cf80Smarks 588ecd6cf80Smarks int 589ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 590ecd6cf80Smarks { 591681d9761SEric Taylor return (zfs_secpolicy_write_perms(name, 592681d9761SEric Taylor ZFS_DELEG_PERM_SNAPSHOT, cr)); 593ecd6cf80Smarks } 594ecd6cf80Smarks 595ecd6cf80Smarks static int 596ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 597ecd6cf80Smarks { 598ecd6cf80Smarks 599ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 600ecd6cf80Smarks } 601ecd6cf80Smarks 602ecd6cf80Smarks static int 603ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 604ecd6cf80Smarks { 605ecd6cf80Smarks char parentname[MAXNAMELEN]; 606ecd6cf80Smarks int error; 607ecd6cf80Smarks 608ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 609ecd6cf80Smarks sizeof (parentname))) != 0) 610ecd6cf80Smarks return (error); 611fa9e4066Sahrens 612ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 613ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 614ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 615ecd6cf80Smarks return (error); 616fa9e4066Sahrens } 617fa9e4066Sahrens 618ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 619ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 620ecd6cf80Smarks return (error); 621ecd6cf80Smarks 622ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 623ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 624ecd6cf80Smarks 625ecd6cf80Smarks return (error); 626ecd6cf80Smarks } 627ecd6cf80Smarks 628ecd6cf80Smarks static int 629ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 630ecd6cf80Smarks { 631ecd6cf80Smarks int error; 632ecd6cf80Smarks 633ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 634ecd6cf80Smarks if (error) { 635ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 636ecd6cf80Smarks } 637ecd6cf80Smarks return (error); 638fa9e4066Sahrens } 639fa9e4066Sahrens 640fa9e4066Sahrens /* 641fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 642fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 643fa9e4066Sahrens */ 644fa9e4066Sahrens /* ARGSUSED */ 645fa9e4066Sahrens static int 646ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 647fa9e4066Sahrens { 648fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 649fa9e4066Sahrens return (EPERM); 650fa9e4066Sahrens 651fa9e4066Sahrens return (0); 652fa9e4066Sahrens } 653fa9e4066Sahrens 654ea8dc4b6Seschrock /* 655ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 656ea8dc4b6Seschrock */ 657ea8dc4b6Seschrock /* ARGSUSED */ 658ea8dc4b6Seschrock static int 659ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 660ea8dc4b6Seschrock { 661ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 662ea8dc4b6Seschrock } 663ea8dc4b6Seschrock 664e45ce728Sahrens static int 665e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 666e45ce728Sahrens { 667e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 668e45ce728Sahrens 669990b4856Slling if (prop == ZPROP_INVAL) { 670e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 671e45ce728Sahrens return (EINVAL); 672e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 673e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 674e45ce728Sahrens } else { 675e45ce728Sahrens if (!zfs_prop_inheritable(prop)) 676e45ce728Sahrens return (EINVAL); 677e45ce728Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 678e45ce728Sahrens } 679e45ce728Sahrens } 680e45ce728Sahrens 68114843421SMatthew Ahrens static int 68214843421SMatthew Ahrens zfs_secpolicy_userspace_one(zfs_cmd_t *zc, cred_t *cr) 68314843421SMatthew Ahrens { 68414843421SMatthew Ahrens int err = zfs_secpolicy_read(zc, cr); 68514843421SMatthew Ahrens if (err) 68614843421SMatthew Ahrens return (err); 68714843421SMatthew Ahrens 68814843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 68914843421SMatthew Ahrens return (EINVAL); 69014843421SMatthew Ahrens 69114843421SMatthew Ahrens if (zc->zc_value[0] == 0) { 69214843421SMatthew Ahrens /* 69314843421SMatthew Ahrens * They are asking about a posix uid/gid. If it's 69414843421SMatthew Ahrens * themself, allow it. 69514843421SMatthew Ahrens */ 69614843421SMatthew Ahrens if (zc->zc_objset_type == ZFS_PROP_USERUSED || 69714843421SMatthew Ahrens zc->zc_objset_type == ZFS_PROP_USERQUOTA) { 69814843421SMatthew Ahrens if (zc->zc_guid == crgetuid(cr)) 69914843421SMatthew Ahrens return (0); 70014843421SMatthew Ahrens } else { 70114843421SMatthew Ahrens if (groupmember(zc->zc_guid, cr)) 70214843421SMatthew Ahrens return (0); 70314843421SMatthew Ahrens } 70414843421SMatthew Ahrens } 70514843421SMatthew Ahrens 70614843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 70714843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 70814843421SMatthew Ahrens } 70914843421SMatthew Ahrens 71014843421SMatthew Ahrens static int 71114843421SMatthew Ahrens zfs_secpolicy_userspace_many(zfs_cmd_t *zc, cred_t *cr) 71214843421SMatthew Ahrens { 71314843421SMatthew Ahrens int err = zfs_secpolicy_read(zc, cr); 71414843421SMatthew Ahrens if (err) 71514843421SMatthew Ahrens return (err); 71614843421SMatthew Ahrens 71714843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 71814843421SMatthew Ahrens return (EINVAL); 71914843421SMatthew Ahrens 72014843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 72114843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 72214843421SMatthew Ahrens } 72314843421SMatthew Ahrens 72414843421SMatthew Ahrens static int 72514843421SMatthew Ahrens zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, cred_t *cr) 72614843421SMatthew Ahrens { 72714843421SMatthew Ahrens return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, cr)); 72814843421SMatthew Ahrens } 72914843421SMatthew Ahrens 730842727c2SChris Kirby static int 731842727c2SChris Kirby zfs_secpolicy_hold(zfs_cmd_t *zc, cred_t *cr) 732842727c2SChris Kirby { 733842727c2SChris Kirby return (zfs_secpolicy_write_perms(zc->zc_name, 734842727c2SChris Kirby ZFS_DELEG_PERM_HOLD, cr)); 735842727c2SChris Kirby } 736842727c2SChris Kirby 737842727c2SChris Kirby static int 738842727c2SChris Kirby zfs_secpolicy_release(zfs_cmd_t *zc, cred_t *cr) 739842727c2SChris Kirby { 740842727c2SChris Kirby return (zfs_secpolicy_write_perms(zc->zc_name, 741842727c2SChris Kirby ZFS_DELEG_PERM_RELEASE, cr)); 742842727c2SChris Kirby } 743842727c2SChris Kirby 744fa9e4066Sahrens /* 745fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 746fa9e4066Sahrens */ 747fa9e4066Sahrens static int 748478ed9adSEric Taylor get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) 749fa9e4066Sahrens { 750fa9e4066Sahrens char *packed; 751fa9e4066Sahrens int error; 752990b4856Slling nvlist_t *list = NULL; 753fa9e4066Sahrens 754fa9e4066Sahrens /* 755e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 756fa9e4066Sahrens */ 757990b4856Slling if (size == 0) 758fa9e4066Sahrens return (EINVAL); 759fa9e4066Sahrens 760fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 761fa9e4066Sahrens 762478ed9adSEric Taylor if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 763478ed9adSEric Taylor iflag)) != 0) { 764fa9e4066Sahrens kmem_free(packed, size); 765fa9e4066Sahrens return (error); 766fa9e4066Sahrens } 767fa9e4066Sahrens 768990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 769fa9e4066Sahrens kmem_free(packed, size); 770fa9e4066Sahrens return (error); 771fa9e4066Sahrens } 772fa9e4066Sahrens 773fa9e4066Sahrens kmem_free(packed, size); 774fa9e4066Sahrens 775990b4856Slling *nvp = list; 776fa9e4066Sahrens return (0); 777fa9e4066Sahrens } 778fa9e4066Sahrens 779e9dbad6fSeschrock static int 780e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 781e9dbad6fSeschrock { 782e9dbad6fSeschrock char *packed = NULL; 783e9dbad6fSeschrock size_t size; 784e9dbad6fSeschrock int error; 785e9dbad6fSeschrock 786e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 787e9dbad6fSeschrock 788e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 789e9dbad6fSeschrock error = ENOMEM; 790e9dbad6fSeschrock } else { 791da165920Smarks packed = kmem_alloc(size, KM_SLEEP); 792e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 793e9dbad6fSeschrock KM_SLEEP) == 0); 794478ed9adSEric Taylor error = ddi_copyout(packed, 795478ed9adSEric Taylor (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags); 796e9dbad6fSeschrock kmem_free(packed, size); 797e9dbad6fSeschrock } 798e9dbad6fSeschrock 799e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 800e9dbad6fSeschrock return (error); 801e9dbad6fSeschrock } 802e9dbad6fSeschrock 80314843421SMatthew Ahrens static int 80414843421SMatthew Ahrens getzfsvfs(const char *dsname, zfsvfs_t **zvp) 80514843421SMatthew Ahrens { 80614843421SMatthew Ahrens objset_t *os; 80714843421SMatthew Ahrens int error; 80814843421SMatthew Ahrens 809503ad85cSMatthew Ahrens error = dmu_objset_hold(dsname, FTAG, &os); 81014843421SMatthew Ahrens if (error) 81114843421SMatthew Ahrens return (error); 812503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 813503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 814503ad85cSMatthew Ahrens return (EINVAL); 815503ad85cSMatthew Ahrens } 81614843421SMatthew Ahrens 817503ad85cSMatthew Ahrens mutex_enter(&os->os_user_ptr_lock); 81814843421SMatthew Ahrens *zvp = dmu_objset_get_user(os); 81914843421SMatthew Ahrens if (*zvp) { 82014843421SMatthew Ahrens VFS_HOLD((*zvp)->z_vfs); 82114843421SMatthew Ahrens } else { 82214843421SMatthew Ahrens error = ESRCH; 82314843421SMatthew Ahrens } 824503ad85cSMatthew Ahrens mutex_exit(&os->os_user_ptr_lock); 825503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 82614843421SMatthew Ahrens return (error); 82714843421SMatthew Ahrens } 82814843421SMatthew Ahrens 82914843421SMatthew Ahrens /* 83014843421SMatthew Ahrens * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 83114843421SMatthew Ahrens * case its z_vfs will be NULL, and it will be opened as the owner. 83214843421SMatthew Ahrens */ 83314843421SMatthew Ahrens static int 834503ad85cSMatthew Ahrens zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zvp) 83514843421SMatthew Ahrens { 83614843421SMatthew Ahrens int error = 0; 83714843421SMatthew Ahrens 83814843421SMatthew Ahrens if (getzfsvfs(name, zvp) != 0) 839503ad85cSMatthew Ahrens error = zfsvfs_create(name, zvp); 84014843421SMatthew Ahrens if (error == 0) { 84114843421SMatthew Ahrens rrw_enter(&(*zvp)->z_teardown_lock, RW_READER, tag); 84214843421SMatthew Ahrens if ((*zvp)->z_unmounted) { 84314843421SMatthew Ahrens /* 84414843421SMatthew Ahrens * XXX we could probably try again, since the unmounting 84514843421SMatthew Ahrens * thread should be just about to disassociate the 84614843421SMatthew Ahrens * objset from the zfsvfs. 84714843421SMatthew Ahrens */ 84814843421SMatthew Ahrens rrw_exit(&(*zvp)->z_teardown_lock, tag); 84914843421SMatthew Ahrens return (EBUSY); 85014843421SMatthew Ahrens } 85114843421SMatthew Ahrens } 85214843421SMatthew Ahrens return (error); 85314843421SMatthew Ahrens } 85414843421SMatthew Ahrens 85514843421SMatthew Ahrens static void 85614843421SMatthew Ahrens zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 85714843421SMatthew Ahrens { 85814843421SMatthew Ahrens rrw_exit(&zfsvfs->z_teardown_lock, tag); 85914843421SMatthew Ahrens 86014843421SMatthew Ahrens if (zfsvfs->z_vfs) { 86114843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 86214843421SMatthew Ahrens } else { 863503ad85cSMatthew Ahrens dmu_objset_disown(zfsvfs->z_os, zfsvfs); 86414843421SMatthew Ahrens zfsvfs_free(zfsvfs); 86514843421SMatthew Ahrens } 86614843421SMatthew Ahrens } 86714843421SMatthew Ahrens 868fa9e4066Sahrens static int 869fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 870fa9e4066Sahrens { 871fa9e4066Sahrens int error; 872990b4856Slling nvlist_t *config, *props = NULL; 8730a48a24eStimh nvlist_t *rootprops = NULL; 8740a48a24eStimh nvlist_t *zplprops = NULL; 875228975ccSek char *buf; 876fa9e4066Sahrens 877990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 878478ed9adSEric Taylor zc->zc_iflags, &config)) 879fa9e4066Sahrens return (error); 8802a6b87f0Sek 881990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 882478ed9adSEric Taylor get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 883478ed9adSEric Taylor zc->zc_iflags, &props))) { 884990b4856Slling nvlist_free(config); 885990b4856Slling return (error); 886990b4856Slling } 887990b4856Slling 8880a48a24eStimh if (props) { 8890a48a24eStimh nvlist_t *nvl = NULL; 8900a48a24eStimh uint64_t version = SPA_VERSION; 8910a48a24eStimh 8920a48a24eStimh (void) nvlist_lookup_uint64(props, 8930a48a24eStimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 8940a48a24eStimh if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 8950a48a24eStimh error = EINVAL; 8960a48a24eStimh goto pool_props_bad; 8970a48a24eStimh } 8980a48a24eStimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 8990a48a24eStimh if (nvl) { 9000a48a24eStimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 9010a48a24eStimh if (error != 0) { 9020a48a24eStimh nvlist_free(config); 9030a48a24eStimh nvlist_free(props); 9040a48a24eStimh return (error); 9050a48a24eStimh } 9060a48a24eStimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 9070a48a24eStimh } 9080a48a24eStimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 9090a48a24eStimh error = zfs_fill_zplprops_root(version, rootprops, 9100a48a24eStimh zplprops, NULL); 9110a48a24eStimh if (error) 9120a48a24eStimh goto pool_props_bad; 9130a48a24eStimh } 9140a48a24eStimh 9152a6b87f0Sek buf = history_str_get(zc); 916fa9e4066Sahrens 9170a48a24eStimh error = spa_create(zc->zc_name, config, props, buf, zplprops); 9180a48a24eStimh 9190a48a24eStimh /* 9200a48a24eStimh * Set the remaining root properties 9210a48a24eStimh */ 9220a48a24eStimh if (!error && 9230a48a24eStimh (error = zfs_set_prop_nvlist(zc->zc_name, rootprops)) != 0) 9240a48a24eStimh (void) spa_destroy(zc->zc_name); 925fa9e4066Sahrens 9262a6b87f0Sek if (buf != NULL) 9272a6b87f0Sek history_str_free(buf); 928990b4856Slling 9290a48a24eStimh pool_props_bad: 9300a48a24eStimh nvlist_free(rootprops); 9310a48a24eStimh nvlist_free(zplprops); 932fa9e4066Sahrens nvlist_free(config); 9330a48a24eStimh nvlist_free(props); 934990b4856Slling 935fa9e4066Sahrens return (error); 936fa9e4066Sahrens } 937fa9e4066Sahrens 938fa9e4066Sahrens static int 939fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 940fa9e4066Sahrens { 941ecd6cf80Smarks int error; 942ecd6cf80Smarks zfs_log_history(zc); 943ecd6cf80Smarks error = spa_destroy(zc->zc_name); 944681d9761SEric Taylor if (error == 0) 945681d9761SEric Taylor zvol_remove_minors(zc->zc_name); 946ecd6cf80Smarks return (error); 947fa9e4066Sahrens } 948fa9e4066Sahrens 949fa9e4066Sahrens static int 950fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 951fa9e4066Sahrens { 952990b4856Slling nvlist_t *config, *props = NULL; 953fa9e4066Sahrens uint64_t guid; 954468c413aSTim Haley int error; 955fa9e4066Sahrens 956990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 957478ed9adSEric Taylor zc->zc_iflags, &config)) != 0) 958990b4856Slling return (error); 959990b4856Slling 960990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 961478ed9adSEric Taylor get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 962478ed9adSEric Taylor zc->zc_iflags, &props))) { 963990b4856Slling nvlist_free(config); 964fa9e4066Sahrens return (error); 965990b4856Slling } 966fa9e4066Sahrens 967fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 968ea8dc4b6Seschrock guid != zc->zc_guid) 969fa9e4066Sahrens error = EINVAL; 970c5904d13Seschrock else if (zc->zc_cookie) 971468c413aSTim Haley error = spa_import_verbatim(zc->zc_name, config, props); 972fa9e4066Sahrens else 973990b4856Slling error = spa_import(zc->zc_name, config, props); 974fa9e4066Sahrens 975468c413aSTim Haley if (zc->zc_nvlist_dst != 0) 976468c413aSTim Haley (void) put_nvlist(zc, config); 977468c413aSTim Haley 978fa9e4066Sahrens nvlist_free(config); 979fa9e4066Sahrens 980990b4856Slling if (props) 981990b4856Slling nvlist_free(props); 982990b4856Slling 983fa9e4066Sahrens return (error); 984fa9e4066Sahrens } 985fa9e4066Sahrens 986fa9e4066Sahrens static int 987fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 988fa9e4066Sahrens { 989ecd6cf80Smarks int error; 99089a89ebfSlling boolean_t force = (boolean_t)zc->zc_cookie; 991394ab0cbSGeorge Wilson boolean_t hardforce = (boolean_t)zc->zc_guid; 99289a89ebfSlling 993ecd6cf80Smarks zfs_log_history(zc); 994394ab0cbSGeorge Wilson error = spa_export(zc->zc_name, NULL, force, hardforce); 995681d9761SEric Taylor if (error == 0) 996681d9761SEric Taylor zvol_remove_minors(zc->zc_name); 997ecd6cf80Smarks return (error); 998fa9e4066Sahrens } 999fa9e4066Sahrens 1000fa9e4066Sahrens static int 1001fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 1002fa9e4066Sahrens { 1003fa9e4066Sahrens nvlist_t *configs; 1004fa9e4066Sahrens int error; 1005fa9e4066Sahrens 1006fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1007fa9e4066Sahrens return (EEXIST); 1008fa9e4066Sahrens 1009e9dbad6fSeschrock error = put_nvlist(zc, configs); 1010fa9e4066Sahrens 1011fa9e4066Sahrens nvlist_free(configs); 1012fa9e4066Sahrens 1013fa9e4066Sahrens return (error); 1014fa9e4066Sahrens } 1015fa9e4066Sahrens 1016fa9e4066Sahrens static int 1017fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 1018fa9e4066Sahrens { 1019fa9e4066Sahrens nvlist_t *config; 1020fa9e4066Sahrens int error; 1021ea8dc4b6Seschrock int ret = 0; 1022fa9e4066Sahrens 1023e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 1024e9dbad6fSeschrock sizeof (zc->zc_value)); 1025fa9e4066Sahrens 1026fa9e4066Sahrens if (config != NULL) { 1027e9dbad6fSeschrock ret = put_nvlist(zc, config); 1028fa9e4066Sahrens nvlist_free(config); 1029ea8dc4b6Seschrock 1030ea8dc4b6Seschrock /* 1031ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 1032ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 1033ea8dc4b6Seschrock * in 'zc_cookie'. 1034ea8dc4b6Seschrock */ 1035ea8dc4b6Seschrock zc->zc_cookie = error; 1036fa9e4066Sahrens } else { 1037ea8dc4b6Seschrock ret = error; 1038fa9e4066Sahrens } 1039fa9e4066Sahrens 1040ea8dc4b6Seschrock return (ret); 1041fa9e4066Sahrens } 1042fa9e4066Sahrens 1043fa9e4066Sahrens /* 1044fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 1045fa9e4066Sahrens * user land knows which devices are available and overall pool health. 1046fa9e4066Sahrens */ 1047fa9e4066Sahrens static int 1048fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1049fa9e4066Sahrens { 1050fa9e4066Sahrens nvlist_t *tryconfig, *config; 1051fa9e4066Sahrens int error; 1052fa9e4066Sahrens 1053990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1054478ed9adSEric Taylor zc->zc_iflags, &tryconfig)) != 0) 1055fa9e4066Sahrens return (error); 1056fa9e4066Sahrens 1057fa9e4066Sahrens config = spa_tryimport(tryconfig); 1058fa9e4066Sahrens 1059fa9e4066Sahrens nvlist_free(tryconfig); 1060fa9e4066Sahrens 1061fa9e4066Sahrens if (config == NULL) 1062fa9e4066Sahrens return (EINVAL); 1063fa9e4066Sahrens 1064e9dbad6fSeschrock error = put_nvlist(zc, config); 1065fa9e4066Sahrens nvlist_free(config); 1066fa9e4066Sahrens 1067fa9e4066Sahrens return (error); 1068fa9e4066Sahrens } 1069fa9e4066Sahrens 1070fa9e4066Sahrens static int 1071fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 1072fa9e4066Sahrens { 1073fa9e4066Sahrens spa_t *spa; 1074fa9e4066Sahrens int error; 1075fa9e4066Sahrens 107606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 107706eeb2adSek return (error); 107806eeb2adSek 1079088f3894Sahrens error = spa_scrub(spa, zc->zc_cookie); 108006eeb2adSek 108106eeb2adSek spa_close(spa, FTAG); 108206eeb2adSek 1083fa9e4066Sahrens return (error); 1084fa9e4066Sahrens } 1085fa9e4066Sahrens 1086fa9e4066Sahrens static int 1087fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 1088fa9e4066Sahrens { 1089fa9e4066Sahrens spa_t *spa; 1090fa9e4066Sahrens int error; 1091fa9e4066Sahrens 1092fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1093fa9e4066Sahrens if (error == 0) { 1094fa9e4066Sahrens spa_freeze(spa); 1095fa9e4066Sahrens spa_close(spa, FTAG); 1096fa9e4066Sahrens } 1097fa9e4066Sahrens return (error); 1098fa9e4066Sahrens } 1099fa9e4066Sahrens 1100eaca9bbdSeschrock static int 1101eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 1102eaca9bbdSeschrock { 1103eaca9bbdSeschrock spa_t *spa; 1104eaca9bbdSeschrock int error; 1105eaca9bbdSeschrock 110606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 110706eeb2adSek return (error); 110806eeb2adSek 1109558d2d50Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 1110558d2d50Slling spa_close(spa, FTAG); 1111558d2d50Slling return (EINVAL); 1112558d2d50Slling } 1113558d2d50Slling 1114990b4856Slling spa_upgrade(spa, zc->zc_cookie); 111506eeb2adSek spa_close(spa, FTAG); 111606eeb2adSek 111706eeb2adSek return (error); 111806eeb2adSek } 111906eeb2adSek 112006eeb2adSek static int 112106eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 112206eeb2adSek { 112306eeb2adSek spa_t *spa; 112406eeb2adSek char *hist_buf; 112506eeb2adSek uint64_t size; 112606eeb2adSek int error; 112706eeb2adSek 112806eeb2adSek if ((size = zc->zc_history_len) == 0) 112906eeb2adSek return (EINVAL); 113006eeb2adSek 113106eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 113206eeb2adSek return (error); 113306eeb2adSek 1134e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1135d7306b64Sek spa_close(spa, FTAG); 1136d7306b64Sek return (ENOTSUP); 1137d7306b64Sek } 1138d7306b64Sek 113906eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 114006eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 114106eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 1142478ed9adSEric Taylor error = ddi_copyout(hist_buf, 1143478ed9adSEric Taylor (void *)(uintptr_t)zc->zc_history, 1144478ed9adSEric Taylor zc->zc_history_len, zc->zc_iflags); 114506eeb2adSek } 114606eeb2adSek 114706eeb2adSek spa_close(spa, FTAG); 114806eeb2adSek kmem_free(hist_buf, size); 114906eeb2adSek return (error); 115006eeb2adSek } 115106eeb2adSek 115255434c77Sek static int 115355434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 115455434c77Sek { 115555434c77Sek int error; 115655434c77Sek 1157b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 115855434c77Sek return (error); 115955434c77Sek 116055434c77Sek return (0); 116155434c77Sek } 116255434c77Sek 1163503ad85cSMatthew Ahrens /* 1164503ad85cSMatthew Ahrens * inputs: 1165503ad85cSMatthew Ahrens * zc_name name of filesystem 1166503ad85cSMatthew Ahrens * zc_obj object to find 1167503ad85cSMatthew Ahrens * 1168503ad85cSMatthew Ahrens * outputs: 1169503ad85cSMatthew Ahrens * zc_value name of object 1170503ad85cSMatthew Ahrens */ 117155434c77Sek static int 117255434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 117355434c77Sek { 1174503ad85cSMatthew Ahrens objset_t *os; 117555434c77Sek int error; 117655434c77Sek 1177503ad85cSMatthew Ahrens /* XXX reading from objset not owned */ 1178503ad85cSMatthew Ahrens if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0) 117955434c77Sek return (error); 1180503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 1181503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 1182503ad85cSMatthew Ahrens return (EINVAL); 1183503ad85cSMatthew Ahrens } 1184503ad85cSMatthew Ahrens error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value, 118555434c77Sek sizeof (zc->zc_value)); 1186503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 118755434c77Sek 118855434c77Sek return (error); 118955434c77Sek } 119055434c77Sek 1191fa9e4066Sahrens static int 1192fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1193fa9e4066Sahrens { 1194fa9e4066Sahrens spa_t *spa; 1195fa9e4066Sahrens int error; 1196e7cbe64fSgw nvlist_t *config, **l2cache, **spares; 1197e7cbe64fSgw uint_t nl2cache = 0, nspares = 0; 1198fa9e4066Sahrens 1199fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1200fa9e4066Sahrens if (error != 0) 1201fa9e4066Sahrens return (error); 1202fa9e4066Sahrens 1203fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1204478ed9adSEric Taylor zc->zc_iflags, &config); 1205fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1206fa94a07fSbrendan &l2cache, &nl2cache); 1207fa94a07fSbrendan 1208e7cbe64fSgw (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1209e7cbe64fSgw &spares, &nspares); 1210e7cbe64fSgw 1211b1b8ab34Slling /* 1212b1b8ab34Slling * A root pool with concatenated devices is not supported. 1213e7cbe64fSgw * Thus, can not add a device to a root pool. 1214e7cbe64fSgw * 1215e7cbe64fSgw * Intent log device can not be added to a rootpool because 1216e7cbe64fSgw * during mountroot, zil is replayed, a seperated log device 1217e7cbe64fSgw * can not be accessed during the mountroot time. 1218e7cbe64fSgw * 1219e7cbe64fSgw * l2cache and spare devices are ok to be added to a rootpool. 1220b1b8ab34Slling */ 1221*b24ab676SJeff Bonwick if (spa_bootfs(spa) != 0 && nl2cache == 0 && nspares == 0) { 1222b1b8ab34Slling spa_close(spa, FTAG); 1223b1b8ab34Slling return (EDOM); 1224b1b8ab34Slling } 1225b1b8ab34Slling 1226fa94a07fSbrendan if (error == 0) { 1227fa9e4066Sahrens error = spa_vdev_add(spa, config); 1228fa9e4066Sahrens nvlist_free(config); 1229fa9e4066Sahrens } 1230fa9e4066Sahrens spa_close(spa, FTAG); 1231fa9e4066Sahrens return (error); 1232fa9e4066Sahrens } 1233fa9e4066Sahrens 1234fa9e4066Sahrens static int 1235fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1236fa9e4066Sahrens { 123799653d4eSeschrock spa_t *spa; 123899653d4eSeschrock int error; 123999653d4eSeschrock 124099653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 124199653d4eSeschrock if (error != 0) 124299653d4eSeschrock return (error); 124399653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 124499653d4eSeschrock spa_close(spa, FTAG); 124599653d4eSeschrock return (error); 1246fa9e4066Sahrens } 1247fa9e4066Sahrens 1248fa9e4066Sahrens static int 12493d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1250fa9e4066Sahrens { 1251fa9e4066Sahrens spa_t *spa; 1252fa9e4066Sahrens int error; 12533d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1254fa9e4066Sahrens 125506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1256fa9e4066Sahrens return (error); 12573d7072f8Seschrock switch (zc->zc_cookie) { 12583d7072f8Seschrock case VDEV_STATE_ONLINE: 12593d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 12603d7072f8Seschrock break; 1261fa9e4066Sahrens 12623d7072f8Seschrock case VDEV_STATE_OFFLINE: 12633d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 12643d7072f8Seschrock break; 1265fa9e4066Sahrens 12663d7072f8Seschrock case VDEV_STATE_FAULTED: 1267069f55e2SEric Schrock if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1268069f55e2SEric Schrock zc->zc_obj != VDEV_AUX_EXTERNAL) 1269069f55e2SEric Schrock zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1270069f55e2SEric Schrock 1271069f55e2SEric Schrock error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); 12723d7072f8Seschrock break; 12733d7072f8Seschrock 12743d7072f8Seschrock case VDEV_STATE_DEGRADED: 1275069f55e2SEric Schrock if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1276069f55e2SEric Schrock zc->zc_obj != VDEV_AUX_EXTERNAL) 1277069f55e2SEric Schrock zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1278069f55e2SEric Schrock 1279069f55e2SEric Schrock error = vdev_degrade(spa, zc->zc_guid, zc->zc_obj); 12803d7072f8Seschrock break; 12813d7072f8Seschrock 12823d7072f8Seschrock default: 12833d7072f8Seschrock error = EINVAL; 12843d7072f8Seschrock } 12853d7072f8Seschrock zc->zc_cookie = newstate; 1286fa9e4066Sahrens spa_close(spa, FTAG); 1287fa9e4066Sahrens return (error); 1288fa9e4066Sahrens } 1289fa9e4066Sahrens 1290fa9e4066Sahrens static int 1291fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1292fa9e4066Sahrens { 1293fa9e4066Sahrens spa_t *spa; 1294fa9e4066Sahrens int replacing = zc->zc_cookie; 1295fa9e4066Sahrens nvlist_t *config; 1296fa9e4066Sahrens int error; 1297fa9e4066Sahrens 129806eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1299fa9e4066Sahrens return (error); 1300fa9e4066Sahrens 1301990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1302478ed9adSEric Taylor zc->zc_iflags, &config)) == 0) { 1303ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1304fa9e4066Sahrens nvlist_free(config); 1305fa9e4066Sahrens } 1306fa9e4066Sahrens 1307fa9e4066Sahrens spa_close(spa, FTAG); 1308fa9e4066Sahrens return (error); 1309fa9e4066Sahrens } 1310fa9e4066Sahrens 1311fa9e4066Sahrens static int 1312fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1313fa9e4066Sahrens { 1314fa9e4066Sahrens spa_t *spa; 1315fa9e4066Sahrens int error; 1316fa9e4066Sahrens 131706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1318fa9e4066Sahrens return (error); 1319fa9e4066Sahrens 13208ad4d6ddSJeff Bonwick error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 1321fa9e4066Sahrens 1322fa9e4066Sahrens spa_close(spa, FTAG); 1323fa9e4066Sahrens return (error); 1324fa9e4066Sahrens } 1325fa9e4066Sahrens 1326c67d9675Seschrock static int 1327c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1328c67d9675Seschrock { 1329c67d9675Seschrock spa_t *spa; 1330e9dbad6fSeschrock char *path = zc->zc_value; 1331ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1332c67d9675Seschrock int error; 1333c67d9675Seschrock 1334c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1335c67d9675Seschrock if (error != 0) 1336c67d9675Seschrock return (error); 1337c67d9675Seschrock 1338c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1339c67d9675Seschrock spa_close(spa, FTAG); 1340c67d9675Seschrock return (error); 1341c67d9675Seschrock } 1342c67d9675Seschrock 13436809eb4eSEric Schrock static int 13446809eb4eSEric Schrock zfs_ioc_vdev_setfru(zfs_cmd_t *zc) 13456809eb4eSEric Schrock { 13466809eb4eSEric Schrock spa_t *spa; 13476809eb4eSEric Schrock char *fru = zc->zc_value; 13486809eb4eSEric Schrock uint64_t guid = zc->zc_guid; 13496809eb4eSEric Schrock int error; 13506809eb4eSEric Schrock 13516809eb4eSEric Schrock error = spa_open(zc->zc_name, &spa, FTAG); 13526809eb4eSEric Schrock if (error != 0) 13536809eb4eSEric Schrock return (error); 13546809eb4eSEric Schrock 13556809eb4eSEric Schrock error = spa_vdev_setfru(spa, guid, fru); 13566809eb4eSEric Schrock spa_close(spa, FTAG); 13576809eb4eSEric Schrock return (error); 13586809eb4eSEric Schrock } 13596809eb4eSEric Schrock 13603cb34c60Sahrens /* 13613cb34c60Sahrens * inputs: 13623cb34c60Sahrens * zc_name name of filesystem 13633cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13643cb34c60Sahrens * 13653cb34c60Sahrens * outputs: 13663cb34c60Sahrens * zc_objset_stats stats 13673cb34c60Sahrens * zc_nvlist_dst property nvlist 13683cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 13693cb34c60Sahrens */ 1370fa9e4066Sahrens static int 1371fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1372fa9e4066Sahrens { 1373fa9e4066Sahrens objset_t *os = NULL; 1374fa9e4066Sahrens int error; 13757f7322feSeschrock nvlist_t *nv; 1376fa9e4066Sahrens 1377503ad85cSMatthew Ahrens if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1378fa9e4066Sahrens return (error); 1379fa9e4066Sahrens 1380a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1381fa9e4066Sahrens 13825ad82045Snd if (zc->zc_nvlist_dst != 0 && 1383745cd3c5Smaybee (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 1384a2eea2e1Sahrens dmu_objset_stats(os, nv); 1385432f72fdSahrens /* 1386bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 1387432f72fdSahrens * which we aren't supposed to do with a 1388745cd3c5Smaybee * DS_MODE_USER hold, because it could be 1389432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1390503ad85cSMatthew Ahrens * XXX reading with out owning 1391432f72fdSahrens */ 1392e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1393e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1394e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1395e7437265Sahrens } 1396e9dbad6fSeschrock error = put_nvlist(zc, nv); 13977f7322feSeschrock nvlist_free(nv); 13987f7322feSeschrock } 1399fa9e4066Sahrens 1400503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 1401fa9e4066Sahrens return (error); 1402fa9e4066Sahrens } 1403fa9e4066Sahrens 1404de8267e0Stimh static int 1405de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1406de8267e0Stimh { 1407de8267e0Stimh uint64_t value; 1408de8267e0Stimh int error; 1409de8267e0Stimh 1410de8267e0Stimh /* 1411de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 1412de8267e0Stimh * the default value (if there is one). 1413de8267e0Stimh */ 1414de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1415de8267e0Stimh return (error); 1416de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1417de8267e0Stimh return (0); 1418de8267e0Stimh } 1419de8267e0Stimh 14203cb34c60Sahrens /* 14213cb34c60Sahrens * inputs: 14223cb34c60Sahrens * zc_name name of filesystem 1423de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 14243cb34c60Sahrens * 14253cb34c60Sahrens * outputs: 1426de8267e0Stimh * zc_nvlist_dst zpl property nvlist 1427de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 14283cb34c60Sahrens */ 1429bd00f61bSrm static int 1430de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1431bd00f61bSrm { 1432de8267e0Stimh objset_t *os; 1433de8267e0Stimh int err; 1434bd00f61bSrm 1435503ad85cSMatthew Ahrens /* XXX reading without owning */ 1436503ad85cSMatthew Ahrens if (err = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1437de8267e0Stimh return (err); 1438bd00f61bSrm 1439bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1440bd00f61bSrm 1441bd00f61bSrm /* 1442de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 1443745cd3c5Smaybee * which we aren't supposed to do with a DS_MODE_USER 1444745cd3c5Smaybee * hold, because it could be inconsistent. 1445bd00f61bSrm */ 1446de8267e0Stimh if (zc->zc_nvlist_dst != NULL && 1447de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 1448de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 1449de8267e0Stimh nvlist_t *nv; 1450de8267e0Stimh 1451de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1452de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1453de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1454de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1455de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1456de8267e0Stimh err = put_nvlist(zc, nv); 1457de8267e0Stimh nvlist_free(nv); 1458de8267e0Stimh } else { 1459de8267e0Stimh err = ENOENT; 1460de8267e0Stimh } 1461503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 1462de8267e0Stimh return (err); 1463bd00f61bSrm } 1464bd00f61bSrm 146514843421SMatthew Ahrens static boolean_t 146614843421SMatthew Ahrens dataset_name_hidden(const char *name) 146714843421SMatthew Ahrens { 146814843421SMatthew Ahrens /* 146914843421SMatthew Ahrens * Skip over datasets that are not visible in this zone, 147014843421SMatthew Ahrens * internal datasets (which have a $ in their name), and 147114843421SMatthew Ahrens * temporary datasets (which have a % in their name). 147214843421SMatthew Ahrens */ 147314843421SMatthew Ahrens if (strchr(name, '$') != NULL) 147414843421SMatthew Ahrens return (B_TRUE); 147514843421SMatthew Ahrens if (strchr(name, '%') != NULL) 147614843421SMatthew Ahrens return (B_TRUE); 147714843421SMatthew Ahrens if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL)) 147814843421SMatthew Ahrens return (B_TRUE); 147914843421SMatthew Ahrens return (B_FALSE); 148014843421SMatthew Ahrens } 148114843421SMatthew Ahrens 1482de8267e0Stimh /* 1483de8267e0Stimh * inputs: 1484de8267e0Stimh * zc_name name of filesystem 1485de8267e0Stimh * zc_cookie zap cursor 1486de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 1487de8267e0Stimh * 1488de8267e0Stimh * outputs: 1489de8267e0Stimh * zc_name name of next filesystem 149014843421SMatthew Ahrens * zc_cookie zap cursor 1491de8267e0Stimh * zc_objset_stats stats 1492de8267e0Stimh * zc_nvlist_dst property nvlist 1493de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 1494de8267e0Stimh */ 1495fa9e4066Sahrens static int 1496fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1497fa9e4066Sahrens { 149887e5029aSahrens objset_t *os; 1499fa9e4066Sahrens int error; 1500fa9e4066Sahrens char *p; 1501fa9e4066Sahrens 1502503ad85cSMatthew Ahrens if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) { 150387e5029aSahrens if (error == ENOENT) 150487e5029aSahrens error = ESRCH; 150587e5029aSahrens return (error); 1506fa9e4066Sahrens } 1507fa9e4066Sahrens 1508fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1509fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1510fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1511fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1512fa9e4066Sahrens 15135c0b6a79SRich Morris /* 15145c0b6a79SRich Morris * Pre-fetch the datasets. dmu_objset_prefetch() always returns 0 15155c0b6a79SRich Morris * but is not declared void because its called by dmu_objset_find(). 15165c0b6a79SRich Morris */ 15177f73c863SRich Morris if (zc->zc_cookie == 0) { 15187f73c863SRich Morris uint64_t cookie = 0; 15197f73c863SRich Morris int len = sizeof (zc->zc_name) - (p - zc->zc_name); 15207f73c863SRich Morris 15217f73c863SRich Morris while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) 15225c0b6a79SRich Morris (void) dmu_objset_prefetch(p, NULL); 15237f73c863SRich Morris } 15247f73c863SRich Morris 1525fa9e4066Sahrens do { 152687e5029aSahrens error = dmu_dir_list_next(os, 152787e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 152887e5029aSahrens NULL, &zc->zc_cookie); 1529fa9e4066Sahrens if (error == ENOENT) 1530fa9e4066Sahrens error = ESRCH; 1531681d9761SEric Taylor } while (error == 0 && dataset_name_hidden(zc->zc_name) && 1532681d9761SEric Taylor !(zc->zc_iflags & FKIOCTL)); 1533503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 1534fa9e4066Sahrens 1535681d9761SEric Taylor /* 1536681d9761SEric Taylor * If it's an internal dataset (ie. with a '$' in its name), 1537681d9761SEric Taylor * don't try to get stats for it, otherwise we'll return ENOENT. 1538681d9761SEric Taylor */ 1539681d9761SEric Taylor if (error == 0 && strchr(zc->zc_name, '$') == NULL) 154087e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1541fa9e4066Sahrens return (error); 1542fa9e4066Sahrens } 1543fa9e4066Sahrens 15443cb34c60Sahrens /* 15453cb34c60Sahrens * inputs: 15463cb34c60Sahrens * zc_name name of filesystem 15473cb34c60Sahrens * zc_cookie zap cursor 15483cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 15493cb34c60Sahrens * 15503cb34c60Sahrens * outputs: 15513cb34c60Sahrens * zc_name name of next snapshot 15523cb34c60Sahrens * zc_objset_stats stats 15533cb34c60Sahrens * zc_nvlist_dst property nvlist 15543cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 15553cb34c60Sahrens */ 1556fa9e4066Sahrens static int 1557fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1558fa9e4066Sahrens { 155987e5029aSahrens objset_t *os; 1560fa9e4066Sahrens int error; 1561fa9e4066Sahrens 15627cbf8b43SRich Morris if (zc->zc_cookie == 0) 15637cbf8b43SRich Morris (void) dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 15647cbf8b43SRich Morris NULL, DS_FIND_SNAPSHOTS); 15657cbf8b43SRich Morris 1566503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &os); 1567745cd3c5Smaybee if (error) 1568745cd3c5Smaybee return (error == ENOENT ? ESRCH : error); 1569fa9e4066Sahrens 1570b81d61a6Slling /* 1571b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1572b81d61a6Slling * so exit immediately. 1573b81d61a6Slling */ 1574b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 1575503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 1576b81d61a6Slling return (ESRCH); 1577fa9e4066Sahrens } 1578fa9e4066Sahrens 157987e5029aSahrens error = dmu_snapshot_list_next(os, 158087e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 1581b38f0970Sck zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 1582503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 158387e5029aSahrens if (error == 0) 158487e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1585745cd3c5Smaybee else if (error == ENOENT) 1586745cd3c5Smaybee error = ESRCH; 1587fa9e4066Sahrens 15883cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 1589745cd3c5Smaybee if (error) 15903cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 1591fa9e4066Sahrens return (error); 1592fa9e4066Sahrens } 1593fa9e4066Sahrens 1594e7cbe64fSgw int 159591ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1596fa9e4066Sahrens { 1597e9dbad6fSeschrock nvpair_t *elem; 15985f389de5SRich Morris int error = 0; 1599e9dbad6fSeschrock uint64_t intval; 1600e9dbad6fSeschrock char *strval; 16015c0b6a79SRich Morris nvlist_t *genericnvl; 160214843421SMatthew Ahrens boolean_t issnap = (strchr(name, '@') != NULL); 1603e9dbad6fSeschrock 1604ecd6cf80Smarks /* 1605ecd6cf80Smarks * First validate permission to set all of the properties 1606ecd6cf80Smarks */ 1607e9dbad6fSeschrock elem = NULL; 1608e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1609db870a07Sahrens const char *propname = nvpair_name(elem); 1610db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1611e9dbad6fSeschrock 1612990b4856Slling if (prop == ZPROP_INVAL) { 1613e9dbad6fSeschrock /* 1614e9dbad6fSeschrock * If this is a user-defined property, it must be a 1615e9dbad6fSeschrock * string, and there is no further validation to do. 1616e9dbad6fSeschrock */ 161714843421SMatthew Ahrens if (zfs_prop_user(propname) && 161814843421SMatthew Ahrens nvpair_type(elem) == DATA_TYPE_STRING) { 161914843421SMatthew Ahrens if (error = zfs_secpolicy_write_perms(name, 162014843421SMatthew Ahrens ZFS_DELEG_PERM_USERPROP, CRED())) 162114843421SMatthew Ahrens return (error); 162214843421SMatthew Ahrens continue; 162314843421SMatthew Ahrens } 1624e9dbad6fSeschrock 162514843421SMatthew Ahrens if (!issnap && zfs_prop_userquota(propname) && 162614843421SMatthew Ahrens nvpair_type(elem) == DATA_TYPE_UINT64_ARRAY) { 162714843421SMatthew Ahrens const char *perm; 162814843421SMatthew Ahrens const char *up = zfs_userquota_prop_prefixes 162914843421SMatthew Ahrens [ZFS_PROP_USERQUOTA]; 163014843421SMatthew Ahrens if (strncmp(propname, up, strlen(up)) == 0) 163114843421SMatthew Ahrens perm = ZFS_DELEG_PERM_USERQUOTA; 163214843421SMatthew Ahrens else 163314843421SMatthew Ahrens perm = ZFS_DELEG_PERM_GROUPQUOTA; 163414843421SMatthew Ahrens if (error = zfs_secpolicy_write_perms(name, 163514843421SMatthew Ahrens perm, CRED())) 163614843421SMatthew Ahrens return (error); 163714843421SMatthew Ahrens continue; 163814843421SMatthew Ahrens } 163914843421SMatthew Ahrens 164014843421SMatthew Ahrens return (EINVAL); 1641e9dbad6fSeschrock } 1642fa9e4066Sahrens 164314843421SMatthew Ahrens if (issnap) 164414843421SMatthew Ahrens return (EINVAL); 164514843421SMatthew Ahrens 164691ebeef5Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1647db870a07Sahrens return (error); 1648db870a07Sahrens 1649e9dbad6fSeschrock /* 1650db870a07Sahrens * Check that this value is valid for this pool version 1651e9dbad6fSeschrock */ 1652e9dbad6fSeschrock switch (prop) { 1653c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1654c9431fa1Sahl /* 1655c9431fa1Sahl * If the user specified gzip compression, make sure 1656c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1657c9431fa1Sahl * we'll catch them later. 1658c9431fa1Sahl */ 1659c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 166015e6edf1Sgw nvpair_value_uint64(elem, &intval) == 0) { 166115e6edf1Sgw if (intval >= ZIO_COMPRESS_GZIP_1 && 166215e6edf1Sgw intval <= ZIO_COMPRESS_GZIP_9 && 16630a48a24eStimh zfs_earlier_version(name, 1664da6c28aaSamw SPA_VERSION_GZIP_COMPRESSION)) 1665da6c28aaSamw return (ENOTSUP); 166615e6edf1Sgw 1667*b24ab676SJeff Bonwick if (intval == ZIO_COMPRESS_ZLE && 1668*b24ab676SJeff Bonwick zfs_earlier_version(name, 1669*b24ab676SJeff Bonwick SPA_VERSION_ZLE_COMPRESSION)) 1670*b24ab676SJeff Bonwick return (ENOTSUP); 1671*b24ab676SJeff Bonwick 167215e6edf1Sgw /* 167315e6edf1Sgw * If this is a bootable dataset then 167415e6edf1Sgw * verify that the compression algorithm 167515e6edf1Sgw * is supported for booting. We must return 167615e6edf1Sgw * something other than ENOTSUP since it 167715e6edf1Sgw * implies a downrev pool version. 167815e6edf1Sgw */ 167915e6edf1Sgw if (zfs_is_bootfs(name) && 168015e6edf1Sgw !BOOTFS_COMPRESS_VALID(intval)) 168115e6edf1Sgw return (ERANGE); 1682c9431fa1Sahl } 1683c9431fa1Sahl break; 168440feaa91Sahrens 168540feaa91Sahrens case ZFS_PROP_COPIES: 168614843421SMatthew Ahrens if (zfs_earlier_version(name, SPA_VERSION_DITTO_BLOCKS)) 1687da6c28aaSamw return (ENOTSUP); 168840feaa91Sahrens break; 16899e6eda55Smarks 1690*b24ab676SJeff Bonwick case ZFS_PROP_DEDUP: 1691*b24ab676SJeff Bonwick if (zfs_earlier_version(name, SPA_VERSION_DEDUP)) 1692*b24ab676SJeff Bonwick return (ENOTSUP); 1693*b24ab676SJeff Bonwick break; 1694*b24ab676SJeff Bonwick 16959e6eda55Smarks case ZFS_PROP_SHARESMB: 1696745cd3c5Smaybee if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 16979e6eda55Smarks return (ENOTSUP); 16989e6eda55Smarks break; 1699d0f3f37eSMark Shellenbaum 1700d0f3f37eSMark Shellenbaum case ZFS_PROP_ACLINHERIT: 1701d0f3f37eSMark Shellenbaum if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1702d0f3f37eSMark Shellenbaum nvpair_value_uint64(elem, &intval) == 0) 1703d0f3f37eSMark Shellenbaum if (intval == ZFS_ACL_PASSTHROUGH_X && 1704d0f3f37eSMark Shellenbaum zfs_earlier_version(name, 1705d0f3f37eSMark Shellenbaum SPA_VERSION_PASSTHROUGH_X)) 1706d0f3f37eSMark Shellenbaum return (ENOTSUP); 170740feaa91Sahrens } 1708ecd6cf80Smarks } 1709ecd6cf80Smarks 17105c0b6a79SRich Morris VERIFY(nvlist_alloc(&genericnvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1711ecd6cf80Smarks elem = NULL; 1712ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1713db870a07Sahrens const char *propname = nvpair_name(elem); 1714db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1715ecd6cf80Smarks 1716990b4856Slling if (prop == ZPROP_INVAL) { 171714843421SMatthew Ahrens if (zfs_prop_userquota(propname)) { 171814843421SMatthew Ahrens uint64_t *valary; 171914843421SMatthew Ahrens unsigned int vallen; 172014843421SMatthew Ahrens const char *domain; 172114843421SMatthew Ahrens zfs_userquota_prop_t type; 172214843421SMatthew Ahrens uint64_t rid; 172314843421SMatthew Ahrens uint64_t quota; 172414843421SMatthew Ahrens zfsvfs_t *zfsvfs; 172514843421SMatthew Ahrens 172614843421SMatthew Ahrens VERIFY(nvpair_value_uint64_array(elem, 172714843421SMatthew Ahrens &valary, &vallen) == 0); 172814843421SMatthew Ahrens VERIFY(vallen == 3); 172914843421SMatthew Ahrens type = valary[0]; 173014843421SMatthew Ahrens rid = valary[1]; 173114843421SMatthew Ahrens quota = valary[2]; 173214843421SMatthew Ahrens domain = propname + 173314843421SMatthew Ahrens strlen(zfs_userquota_prop_prefixes[type]); 173414843421SMatthew Ahrens 1735503ad85cSMatthew Ahrens error = zfsvfs_hold(name, FTAG, &zfsvfs); 173614843421SMatthew Ahrens if (error == 0) { 173714843421SMatthew Ahrens error = zfs_set_userquota(zfsvfs, 173814843421SMatthew Ahrens type, domain, rid, quota); 173914843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 174014843421SMatthew Ahrens } 174114843421SMatthew Ahrens if (error == 0) 174214843421SMatthew Ahrens continue; 174314843421SMatthew Ahrens else 174414843421SMatthew Ahrens goto out; 174514843421SMatthew Ahrens } else if (zfs_prop_user(propname)) { 174614843421SMatthew Ahrens VERIFY(nvpair_value_string(elem, &strval) == 0); 174714843421SMatthew Ahrens error = dsl_prop_set(name, propname, 1, 174814843421SMatthew Ahrens strlen(strval) + 1, strval); 174914843421SMatthew Ahrens if (error == 0) 175014843421SMatthew Ahrens continue; 175114843421SMatthew Ahrens else 175214843421SMatthew Ahrens goto out; 175314843421SMatthew Ahrens } 1754ecd6cf80Smarks } 1755e9dbad6fSeschrock 1756e9dbad6fSeschrock switch (prop) { 1757e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1758e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1759e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 17605c0b6a79SRich Morris goto out; 1761e9dbad6fSeschrock break; 1762e9dbad6fSeschrock 1763a9799022Sck case ZFS_PROP_REFQUOTA: 1764a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1765a9799022Sck (error = dsl_dataset_set_quota(name, intval)) != 0) 17665c0b6a79SRich Morris goto out; 1767a9799022Sck break; 1768a9799022Sck 1769e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1770e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1771e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1772e9dbad6fSeschrock intval)) != 0) 17735c0b6a79SRich Morris goto out; 1774e9dbad6fSeschrock break; 1775e9dbad6fSeschrock 1776a9799022Sck case ZFS_PROP_REFRESERVATION: 1777a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1778a9799022Sck (error = dsl_dataset_set_reservation(name, 1779a9799022Sck intval)) != 0) 17805c0b6a79SRich Morris goto out; 1781a9799022Sck break; 1782a9799022Sck 1783e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1784e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 178591ebeef5Sahrens (error = zvol_set_volsize(name, 178691ebeef5Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 17875c0b6a79SRich Morris goto out; 1788e9dbad6fSeschrock break; 1789e9dbad6fSeschrock 1790e7437265Sahrens case ZFS_PROP_VERSION: 179114843421SMatthew Ahrens { 179214843421SMatthew Ahrens zfsvfs_t *zfsvfs; 179314843421SMatthew Ahrens 179414843421SMatthew Ahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0) 179514843421SMatthew Ahrens goto out; 1796503ad85cSMatthew Ahrens if ((error = zfsvfs_hold(name, FTAG, &zfsvfs)) != 0) 179714843421SMatthew Ahrens goto out; 179814843421SMatthew Ahrens error = zfs_set_version(zfsvfs, intval); 179914843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 180014843421SMatthew Ahrens 180114843421SMatthew Ahrens if (error == 0 && intval >= ZPL_VERSION_USERSPACE) { 180214843421SMatthew Ahrens zfs_cmd_t zc = { 0 }; 180314843421SMatthew Ahrens (void) strcpy(zc.zc_name, name); 180414843421SMatthew Ahrens (void) zfs_ioc_userspace_upgrade(&zc); 180514843421SMatthew Ahrens } 180614843421SMatthew Ahrens if (error) 18075c0b6a79SRich Morris goto out; 1808e9dbad6fSeschrock break; 180914843421SMatthew Ahrens } 1810e9dbad6fSeschrock 1811e9dbad6fSeschrock default: 1812e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1813e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 18145c0b6a79SRich Morris PROP_TYPE_STRING) { 18155c0b6a79SRich Morris error = EINVAL; 18165c0b6a79SRich Morris goto out; 18175c0b6a79SRich Morris } 1818e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1819a2eea2e1Sahrens const char *unused; 1820a2eea2e1Sahrens 1821acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1822e9dbad6fSeschrock 1823e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 182491ebeef5Sahrens case PROP_TYPE_NUMBER: 1825e9dbad6fSeschrock break; 182691ebeef5Sahrens case PROP_TYPE_STRING: 18275c0b6a79SRich Morris error = EINVAL; 18285c0b6a79SRich Morris goto out; 182991ebeef5Sahrens case PROP_TYPE_INDEX: 1830acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 18315c0b6a79SRich Morris intval, &unused) != 0) { 18325c0b6a79SRich Morris error = EINVAL; 18335c0b6a79SRich Morris goto out; 18345c0b6a79SRich Morris } 1835e9dbad6fSeschrock break; 1836e9dbad6fSeschrock default: 1837e7437265Sahrens cmn_err(CE_PANIC, 1838e7437265Sahrens "unknown property type"); 1839e9dbad6fSeschrock break; 1840e9dbad6fSeschrock } 1841e9dbad6fSeschrock } else { 18425c0b6a79SRich Morris error = EINVAL; 18435c0b6a79SRich Morris goto out; 1844e9dbad6fSeschrock } 18455c0b6a79SRich Morris if ((error = nvlist_add_nvpair(genericnvl, elem)) != 0) 18465c0b6a79SRich Morris goto out; 1847e9dbad6fSeschrock } 1848e9dbad6fSeschrock } 1849e9dbad6fSeschrock 18505c0b6a79SRich Morris if (nvlist_next_nvpair(genericnvl, NULL) != NULL) { 18515c0b6a79SRich Morris error = dsl_props_set(name, genericnvl); 18525c0b6a79SRich Morris } 18535c0b6a79SRich Morris out: 18545c0b6a79SRich Morris nvlist_free(genericnvl); 18555c0b6a79SRich Morris return (error); 1856fa9e4066Sahrens } 1857fa9e4066Sahrens 1858ea2f5b9eSMatthew Ahrens /* 1859ea2f5b9eSMatthew Ahrens * Check that all the properties are valid user properties. 1860ea2f5b9eSMatthew Ahrens */ 1861ea2f5b9eSMatthew Ahrens static int 1862ea2f5b9eSMatthew Ahrens zfs_check_userprops(char *fsname, nvlist_t *nvl) 1863ea2f5b9eSMatthew Ahrens { 1864ea2f5b9eSMatthew Ahrens nvpair_t *elem = NULL; 1865ea2f5b9eSMatthew Ahrens int error = 0; 1866ea2f5b9eSMatthew Ahrens 1867ea2f5b9eSMatthew Ahrens while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1868ea2f5b9eSMatthew Ahrens const char *propname = nvpair_name(elem); 1869ea2f5b9eSMatthew Ahrens char *valstr; 1870ea2f5b9eSMatthew Ahrens 1871ea2f5b9eSMatthew Ahrens if (!zfs_prop_user(propname) || 1872ea2f5b9eSMatthew Ahrens nvpair_type(elem) != DATA_TYPE_STRING) 1873ea2f5b9eSMatthew Ahrens return (EINVAL); 1874ea2f5b9eSMatthew Ahrens 1875ea2f5b9eSMatthew Ahrens if (error = zfs_secpolicy_write_perms(fsname, 1876ea2f5b9eSMatthew Ahrens ZFS_DELEG_PERM_USERPROP, CRED())) 1877ea2f5b9eSMatthew Ahrens return (error); 1878ea2f5b9eSMatthew Ahrens 1879ea2f5b9eSMatthew Ahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 1880ea2f5b9eSMatthew Ahrens return (ENAMETOOLONG); 1881ea2f5b9eSMatthew Ahrens 1882ea2f5b9eSMatthew Ahrens VERIFY(nvpair_value_string(elem, &valstr) == 0); 1883ea2f5b9eSMatthew Ahrens if (strlen(valstr) >= ZAP_MAXVALUELEN) 1884ea2f5b9eSMatthew Ahrens return (E2BIG); 1885ea2f5b9eSMatthew Ahrens } 1886ea2f5b9eSMatthew Ahrens return (0); 1887ea2f5b9eSMatthew Ahrens } 1888ea2f5b9eSMatthew Ahrens 18893cb34c60Sahrens /* 18903cb34c60Sahrens * inputs: 18913cb34c60Sahrens * zc_name name of filesystem 18925c0b6a79SRich Morris * zc_value name of property to set 18933cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 1894bb0ade09Sahrens * zc_cookie clear existing local props? 18953cb34c60Sahrens * 18963cb34c60Sahrens * outputs: none 18973cb34c60Sahrens */ 1898fa9e4066Sahrens static int 1899e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1900fa9e4066Sahrens { 1901e9dbad6fSeschrock nvlist_t *nvl; 1902e9dbad6fSeschrock int error; 1903e9dbad6fSeschrock 1904990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1905478ed9adSEric Taylor zc->zc_iflags, &nvl)) != 0) 1906e9dbad6fSeschrock return (error); 1907e9dbad6fSeschrock 1908bb0ade09Sahrens if (zc->zc_cookie) { 1909bb0ade09Sahrens nvlist_t *origprops; 1910bb0ade09Sahrens objset_t *os; 1911bb0ade09Sahrens 1912503ad85cSMatthew Ahrens if (dmu_objset_hold(zc->zc_name, FTAG, &os) == 0) { 1913bb0ade09Sahrens if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 19146e77af0aSDavid Pacheco clear_props(zc->zc_name, origprops, nvl); 1915bb0ade09Sahrens nvlist_free(origprops); 1916bb0ade09Sahrens } 1917503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 1918bb0ade09Sahrens } 1919bb0ade09Sahrens 1920bb0ade09Sahrens } 1921bb0ade09Sahrens 192291ebeef5Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1923ecd6cf80Smarks 1924e9dbad6fSeschrock nvlist_free(nvl); 1925e9dbad6fSeschrock return (error); 1926fa9e4066Sahrens } 1927fa9e4066Sahrens 19283cb34c60Sahrens /* 19293cb34c60Sahrens * inputs: 19303cb34c60Sahrens * zc_name name of filesystem 19313cb34c60Sahrens * zc_value name of property to inherit 19323cb34c60Sahrens * 19333cb34c60Sahrens * outputs: none 19343cb34c60Sahrens */ 1935e45ce728Sahrens static int 1936e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 1937e45ce728Sahrens { 1938e45ce728Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 1939e45ce728Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1940e45ce728Sahrens } 1941e45ce728Sahrens 1942b1b8ab34Slling static int 194311a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1944b1b8ab34Slling { 1945990b4856Slling nvlist_t *props; 1946b1b8ab34Slling spa_t *spa; 1947990b4856Slling int error; 1948379c004dSEric Schrock nvpair_t *elem; 1949b1b8ab34Slling 1950990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1951478ed9adSEric Taylor zc->zc_iflags, &props))) 1952b1b8ab34Slling return (error); 1953b1b8ab34Slling 1954379c004dSEric Schrock /* 1955379c004dSEric Schrock * If the only property is the configfile, then just do a spa_lookup() 1956379c004dSEric Schrock * to handle the faulted case. 1957379c004dSEric Schrock */ 1958379c004dSEric Schrock elem = nvlist_next_nvpair(props, NULL); 1959379c004dSEric Schrock if (elem != NULL && strcmp(nvpair_name(elem), 1960379c004dSEric Schrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 1961379c004dSEric Schrock nvlist_next_nvpair(props, elem) == NULL) { 1962379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 1963379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) { 1964379c004dSEric Schrock spa_configfile_set(spa, props, B_FALSE); 1965379c004dSEric Schrock spa_config_sync(spa, B_FALSE, B_TRUE); 1966379c004dSEric Schrock } 1967379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 1968b693757aSEric Schrock if (spa != NULL) { 1969b693757aSEric Schrock nvlist_free(props); 1970379c004dSEric Schrock return (0); 1971b693757aSEric Schrock } 1972379c004dSEric Schrock } 1973379c004dSEric Schrock 1974b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1975990b4856Slling nvlist_free(props); 1976b1b8ab34Slling return (error); 1977b1b8ab34Slling } 1978b1b8ab34Slling 1979990b4856Slling error = spa_prop_set(spa, props); 1980b1b8ab34Slling 1981990b4856Slling nvlist_free(props); 1982b1b8ab34Slling spa_close(spa, FTAG); 1983b1b8ab34Slling 1984b1b8ab34Slling return (error); 1985b1b8ab34Slling } 1986b1b8ab34Slling 1987b1b8ab34Slling static int 198811a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1989b1b8ab34Slling { 1990b1b8ab34Slling spa_t *spa; 1991b1b8ab34Slling int error; 1992b1b8ab34Slling nvlist_t *nvp = NULL; 1993b1b8ab34Slling 1994379c004dSEric Schrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1995379c004dSEric Schrock /* 1996379c004dSEric Schrock * If the pool is faulted, there may be properties we can still 1997379c004dSEric Schrock * get (such as altroot and cachefile), so attempt to get them 1998379c004dSEric Schrock * anyway. 1999379c004dSEric Schrock */ 2000379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 2001379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) 2002379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 2003379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 2004379c004dSEric Schrock } else { 2005379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 2006379c004dSEric Schrock spa_close(spa, FTAG); 2007379c004dSEric Schrock } 2008b1b8ab34Slling 2009b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 2010b1b8ab34Slling error = put_nvlist(zc, nvp); 2011b1b8ab34Slling else 2012b1b8ab34Slling error = EFAULT; 2013b1b8ab34Slling 2014379c004dSEric Schrock nvlist_free(nvp); 2015b1b8ab34Slling return (error); 2016b1b8ab34Slling } 2017b1b8ab34Slling 2018ecd6cf80Smarks static int 2019ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 2020ecd6cf80Smarks { 2021ecd6cf80Smarks nvlist_t *nvp; 2022ecd6cf80Smarks int error; 2023ecd6cf80Smarks uint32_t uid; 2024ecd6cf80Smarks uint32_t gid; 2025ecd6cf80Smarks uint32_t *groups; 2026ecd6cf80Smarks uint_t group_cnt; 2027ecd6cf80Smarks cred_t *usercred; 2028ecd6cf80Smarks 2029990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2030478ed9adSEric Taylor zc->zc_iflags, &nvp)) != 0) { 2031ecd6cf80Smarks return (error); 2032ecd6cf80Smarks } 2033ecd6cf80Smarks 2034ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 2035ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 2036ecd6cf80Smarks nvlist_free(nvp); 2037ecd6cf80Smarks return (EPERM); 2038ecd6cf80Smarks } 2039ecd6cf80Smarks 2040ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 2041ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 2042ecd6cf80Smarks nvlist_free(nvp); 2043ecd6cf80Smarks return (EPERM); 2044ecd6cf80Smarks } 2045ecd6cf80Smarks 2046ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 2047ecd6cf80Smarks &groups, &group_cnt)) != 0) { 2048ecd6cf80Smarks nvlist_free(nvp); 2049ecd6cf80Smarks return (EPERM); 2050ecd6cf80Smarks } 2051ecd6cf80Smarks usercred = cralloc(); 2052ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 2053ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 2054ecd6cf80Smarks nvlist_free(nvp); 2055ecd6cf80Smarks crfree(usercred); 2056ecd6cf80Smarks return (EPERM); 2057ecd6cf80Smarks } 2058ecd6cf80Smarks nvlist_free(nvp); 2059ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 206091ebeef5Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 2061ecd6cf80Smarks crfree(usercred); 2062ecd6cf80Smarks return (error); 2063ecd6cf80Smarks } 2064ecd6cf80Smarks 20653cb34c60Sahrens /* 20663cb34c60Sahrens * inputs: 20673cb34c60Sahrens * zc_name name of filesystem 20683cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 20693cb34c60Sahrens * zc_perm_action allow/unallow flag 20703cb34c60Sahrens * 20713cb34c60Sahrens * outputs: none 20723cb34c60Sahrens */ 2073ecd6cf80Smarks static int 2074ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 2075ecd6cf80Smarks { 2076ecd6cf80Smarks int error; 2077ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 2078ecd6cf80Smarks 2079990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2080478ed9adSEric Taylor zc->zc_iflags, &fsaclnv)) != 0) 2081ecd6cf80Smarks return (error); 2082ecd6cf80Smarks 2083ecd6cf80Smarks /* 2084ecd6cf80Smarks * Verify nvlist is constructed correctly 2085ecd6cf80Smarks */ 2086ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 2087ecd6cf80Smarks nvlist_free(fsaclnv); 2088ecd6cf80Smarks return (EINVAL); 2089ecd6cf80Smarks } 2090ecd6cf80Smarks 2091ecd6cf80Smarks /* 2092ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 2093ecd6cf80Smarks * that user is allowed to hand out each permission in 2094ecd6cf80Smarks * the nvlist(s) 2095ecd6cf80Smarks */ 2096ecd6cf80Smarks 209791ebeef5Sahrens error = secpolicy_zfs(CRED()); 2098ecd6cf80Smarks if (error) { 209991ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 210091ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 210191ebeef5Sahrens fsaclnv, CRED()); 210291ebeef5Sahrens } else { 210391ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 210491ebeef5Sahrens fsaclnv, CRED()); 210591ebeef5Sahrens } 2106ecd6cf80Smarks } 2107ecd6cf80Smarks 2108ecd6cf80Smarks if (error == 0) 2109ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 2110ecd6cf80Smarks 2111ecd6cf80Smarks nvlist_free(fsaclnv); 2112ecd6cf80Smarks return (error); 2113ecd6cf80Smarks } 2114ecd6cf80Smarks 21153cb34c60Sahrens /* 21163cb34c60Sahrens * inputs: 21173cb34c60Sahrens * zc_name name of filesystem 21183cb34c60Sahrens * 21193cb34c60Sahrens * outputs: 21203cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 21213cb34c60Sahrens */ 2122ecd6cf80Smarks static int 2123ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 2124ecd6cf80Smarks { 2125ecd6cf80Smarks nvlist_t *nvp; 2126ecd6cf80Smarks int error; 2127ecd6cf80Smarks 2128ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 2129ecd6cf80Smarks error = put_nvlist(zc, nvp); 2130ecd6cf80Smarks nvlist_free(nvp); 2131ecd6cf80Smarks } 2132ecd6cf80Smarks 2133ecd6cf80Smarks return (error); 2134ecd6cf80Smarks } 2135ecd6cf80Smarks 2136fa9e4066Sahrens /* 2137fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 2138fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 2139fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 2140fa9e4066Sahrens */ 2141fa9e4066Sahrens static vfs_t * 2142fa9e4066Sahrens zfs_get_vfs(const char *resource) 2143fa9e4066Sahrens { 2144fa9e4066Sahrens struct vfs *vfsp; 2145fa9e4066Sahrens struct vfs *vfs_found = NULL; 2146fa9e4066Sahrens 2147fa9e4066Sahrens vfs_list_read_lock(); 2148fa9e4066Sahrens vfsp = rootvfs; 2149fa9e4066Sahrens do { 2150fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 2151fa9e4066Sahrens VFS_HOLD(vfsp); 2152fa9e4066Sahrens vfs_found = vfsp; 2153fa9e4066Sahrens break; 2154fa9e4066Sahrens } 2155fa9e4066Sahrens vfsp = vfsp->vfs_next; 2156fa9e4066Sahrens } while (vfsp != rootvfs); 2157fa9e4066Sahrens vfs_list_unlock(); 2158fa9e4066Sahrens return (vfs_found); 2159fa9e4066Sahrens } 2160fa9e4066Sahrens 2161ecd6cf80Smarks /* ARGSUSED */ 2162fa9e4066Sahrens static void 2163ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 2164fa9e4066Sahrens { 2165da6c28aaSamw zfs_creat_t *zct = arg; 2166da6c28aaSamw 2167de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 2168da6c28aaSamw } 2169da6c28aaSamw 2170de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 2171da6c28aaSamw 2172da6c28aaSamw /* 2173de8267e0Stimh * inputs: 21740a48a24eStimh * createprops list of properties requested by creator 21750a48a24eStimh * default_zplver zpl version to use if unspecified in createprops 21760a48a24eStimh * fuids_ok fuids allowed in this version of the spa? 21770a48a24eStimh * os parent objset pointer (NULL if root fs) 2178de8267e0Stimh * 2179de8267e0Stimh * outputs: 2180de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 21810a48a24eStimh * is_ci true if requested file system will be purely case-insensitive 2182da6c28aaSamw * 2183de8267e0Stimh * Determine the settings for utf8only, normalization and 2184de8267e0Stimh * casesensitivity. Specific values may have been requested by the 2185de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 2186de8267e0Stimh * the file system is of too early a vintage, a creator can not 2187de8267e0Stimh * request settings for these properties, even if the requested 2188de8267e0Stimh * setting is the default value. We don't actually want to create dsl 2189de8267e0Stimh * properties for these, so remove them from the source nvlist after 2190de8267e0Stimh * processing. 2191da6c28aaSamw */ 2192da6c28aaSamw static int 219314843421SMatthew Ahrens zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 21940a48a24eStimh boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 21950a48a24eStimh boolean_t *is_ci) 2196da6c28aaSamw { 2197de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 2198de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 2199de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 2200da6c28aaSamw 2201de8267e0Stimh ASSERT(zplprops != NULL); 2202da6c28aaSamw 2203de8267e0Stimh /* 2204de8267e0Stimh * Pull out creator prop choices, if any. 2205de8267e0Stimh */ 2206de8267e0Stimh if (createprops) { 22070a48a24eStimh (void) nvlist_lookup_uint64(createprops, 22080a48a24eStimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 2209de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 2210de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 2211de8267e0Stimh (void) nvlist_remove_all(createprops, 2212de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 2213de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 2214de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 2215de8267e0Stimh (void) nvlist_remove_all(createprops, 2216de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 2217de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 2218de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 2219de8267e0Stimh (void) nvlist_remove_all(createprops, 2220de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 2221de8267e0Stimh } 2222da6c28aaSamw 2223c2a93d44Stimh /* 22240a48a24eStimh * If the zpl version requested is whacky or the file system 22250a48a24eStimh * or pool is version is too "young" to support normalization 22260a48a24eStimh * and the creator tried to set a value for one of the props, 22270a48a24eStimh * error out. 2228c2a93d44Stimh */ 22290a48a24eStimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 22300a48a24eStimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 22310a48a24eStimh (zplver < ZPL_VERSION_NORMALIZATION && 2232de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 22330a48a24eStimh sense != ZFS_PROP_UNDEFINED))) 2234de8267e0Stimh return (ENOTSUP); 2235c2a93d44Stimh 2236de8267e0Stimh /* 2237de8267e0Stimh * Put the version in the zplprops 2238de8267e0Stimh */ 2239de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2240de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 2241da6c28aaSamw 2242de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 2243de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 2244de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2245de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 2246da6c28aaSamw 2247c2a93d44Stimh /* 2248de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 2249c2a93d44Stimh */ 2250de8267e0Stimh if (norm) 2251de8267e0Stimh u8 = 1; 2252de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 2253de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 2254de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2255de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 2256de8267e0Stimh 2257de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 2258de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 2259de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2260de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 2261c2a93d44Stimh 2262ab04eb8eStimh if (is_ci) 2263ab04eb8eStimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 2264ab04eb8eStimh 2265da6c28aaSamw return (0); 2266fa9e4066Sahrens } 2267fa9e4066Sahrens 22680a48a24eStimh static int 22690a48a24eStimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 22700a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 22710a48a24eStimh { 22720a48a24eStimh boolean_t fuids_ok = B_TRUE; 22730a48a24eStimh uint64_t zplver = ZPL_VERSION; 22740a48a24eStimh objset_t *os = NULL; 22750a48a24eStimh char parentname[MAXNAMELEN]; 22760a48a24eStimh char *cp; 22770a48a24eStimh int error; 22780a48a24eStimh 22790a48a24eStimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 22800a48a24eStimh cp = strrchr(parentname, '/'); 22810a48a24eStimh ASSERT(cp != NULL); 22820a48a24eStimh cp[0] = '\0'; 22830a48a24eStimh 228414843421SMatthew Ahrens if (zfs_earlier_version(dataset, SPA_VERSION_USERSPACE)) 228514843421SMatthew Ahrens zplver = ZPL_VERSION_USERSPACE - 1; 22860a48a24eStimh if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 22870a48a24eStimh zplver = ZPL_VERSION_FUID - 1; 22880a48a24eStimh fuids_ok = B_FALSE; 22890a48a24eStimh } 22900a48a24eStimh 22910a48a24eStimh /* 22920a48a24eStimh * Open parent object set so we can inherit zplprop values. 22930a48a24eStimh */ 2294503ad85cSMatthew Ahrens if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0) 22950a48a24eStimh return (error); 22960a48a24eStimh 22970a48a24eStimh error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 22980a48a24eStimh zplprops, is_ci); 2299503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 23000a48a24eStimh return (error); 23010a48a24eStimh } 23020a48a24eStimh 23030a48a24eStimh static int 23040a48a24eStimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 23050a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 23060a48a24eStimh { 23070a48a24eStimh boolean_t fuids_ok = B_TRUE; 23080a48a24eStimh uint64_t zplver = ZPL_VERSION; 23090a48a24eStimh int error; 23100a48a24eStimh 23110a48a24eStimh if (spa_vers < SPA_VERSION_FUID) { 23120a48a24eStimh zplver = ZPL_VERSION_FUID - 1; 23130a48a24eStimh fuids_ok = B_FALSE; 23140a48a24eStimh } 23150a48a24eStimh 23160a48a24eStimh error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 23170a48a24eStimh zplprops, is_ci); 23180a48a24eStimh return (error); 23190a48a24eStimh } 23200a48a24eStimh 23213cb34c60Sahrens /* 23223cb34c60Sahrens * inputs: 23233cb34c60Sahrens * zc_objset_type type of objset to create (fs vs zvol) 23243cb34c60Sahrens * zc_name name of new objset 23253cb34c60Sahrens * zc_value name of snapshot to clone from (may be empty) 23263cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 23273cb34c60Sahrens * 2328de8267e0Stimh * outputs: none 23293cb34c60Sahrens */ 2330fa9e4066Sahrens static int 2331fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 2332fa9e4066Sahrens { 2333fa9e4066Sahrens objset_t *clone; 2334fa9e4066Sahrens int error = 0; 2335da6c28aaSamw zfs_creat_t zct; 2336ecd6cf80Smarks nvlist_t *nvprops = NULL; 2337ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2338fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 2339fa9e4066Sahrens 2340fa9e4066Sahrens switch (type) { 2341fa9e4066Sahrens 2342fa9e4066Sahrens case DMU_OST_ZFS: 2343fa9e4066Sahrens cbfunc = zfs_create_cb; 2344fa9e4066Sahrens break; 2345fa9e4066Sahrens 2346fa9e4066Sahrens case DMU_OST_ZVOL: 2347fa9e4066Sahrens cbfunc = zvol_create_cb; 2348fa9e4066Sahrens break; 2349fa9e4066Sahrens 2350fa9e4066Sahrens default: 23511d452cf5Sahrens cbfunc = NULL; 2352e7cbe64fSgw break; 2353fa9e4066Sahrens } 2354f18faf3fSek if (strchr(zc->zc_name, '@') || 2355f18faf3fSek strchr(zc->zc_name, '%')) 23561d452cf5Sahrens return (EINVAL); 2357fa9e4066Sahrens 2358e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 2359990b4856Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2360478ed9adSEric Taylor zc->zc_iflags, &nvprops)) != 0) 2361e9dbad6fSeschrock return (error); 2362e9dbad6fSeschrock 2363de8267e0Stimh zct.zct_zplprops = NULL; 2364da6c28aaSamw zct.zct_props = nvprops; 2365da6c28aaSamw 2366e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 2367fa9e4066Sahrens /* 2368fa9e4066Sahrens * We're creating a clone of an existing snapshot. 2369fa9e4066Sahrens */ 2370e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2371e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 2372ecd6cf80Smarks nvlist_free(nvprops); 2373fa9e4066Sahrens return (EINVAL); 2374e9dbad6fSeschrock } 2375fa9e4066Sahrens 2376503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_value, FTAG, &clone); 2377e9dbad6fSeschrock if (error) { 2378ecd6cf80Smarks nvlist_free(nvprops); 2379fa9e4066Sahrens return (error); 2380e9dbad6fSeschrock } 2381ab04eb8eStimh 2382ae46e4c7SMatthew Ahrens error = dmu_objset_clone(zc->zc_name, dmu_objset_ds(clone), 0); 2383503ad85cSMatthew Ahrens dmu_objset_rele(clone, FTAG); 2384da6c28aaSamw if (error) { 2385da6c28aaSamw nvlist_free(nvprops); 2386da6c28aaSamw return (error); 2387da6c28aaSamw } 2388fa9e4066Sahrens } else { 2389ab04eb8eStimh boolean_t is_insensitive = B_FALSE; 2390ab04eb8eStimh 2391e9dbad6fSeschrock if (cbfunc == NULL) { 2392ecd6cf80Smarks nvlist_free(nvprops); 23931d452cf5Sahrens return (EINVAL); 2394e9dbad6fSeschrock } 23955c5460e9Seschrock 2396e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 2397e9dbad6fSeschrock uint64_t volsize, volblocksize; 2398e9dbad6fSeschrock 2399ecd6cf80Smarks if (nvprops == NULL || 2400ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 2401e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 2402e9dbad6fSeschrock &volsize) != 0) { 2403ecd6cf80Smarks nvlist_free(nvprops); 2404e9dbad6fSeschrock return (EINVAL); 2405e9dbad6fSeschrock } 2406e9dbad6fSeschrock 2407ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 2408e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2409e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 2410ecd6cf80Smarks nvlist_free(nvprops); 2411e9dbad6fSeschrock return (EINVAL); 2412e9dbad6fSeschrock } 2413e9dbad6fSeschrock 2414e9dbad6fSeschrock if (error != 0) 2415e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 2416e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 2417e9dbad6fSeschrock 2418e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 2419e9dbad6fSeschrock volblocksize)) != 0 || 2420e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 2421e9dbad6fSeschrock volblocksize)) != 0) { 2422ecd6cf80Smarks nvlist_free(nvprops); 24235c5460e9Seschrock return (error); 2424e9dbad6fSeschrock } 2425e7437265Sahrens } else if (type == DMU_OST_ZFS) { 2426da6c28aaSamw int error; 2427da6c28aaSamw 2428da6c28aaSamw /* 2429da6c28aaSamw * We have to have normalization and 2430da6c28aaSamw * case-folding flags correct when we do the 2431da6c28aaSamw * file system creation, so go figure them out 2432de8267e0Stimh * now. 2433da6c28aaSamw */ 2434de8267e0Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 2435de8267e0Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 2436de8267e0Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 24370a48a24eStimh zct.zct_zplprops, &is_insensitive); 2438da6c28aaSamw if (error != 0) { 2439da6c28aaSamw nvlist_free(nvprops); 2440de8267e0Stimh nvlist_free(zct.zct_zplprops); 2441da6c28aaSamw return (error); 2442da6c28aaSamw } 2443da6c28aaSamw } 2444ae46e4c7SMatthew Ahrens error = dmu_objset_create(zc->zc_name, type, 2445ab04eb8eStimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 2446de8267e0Stimh nvlist_free(zct.zct_zplprops); 2447fa9e4066Sahrens } 2448e9dbad6fSeschrock 2449e9dbad6fSeschrock /* 2450e9dbad6fSeschrock * It would be nice to do this atomically. 2451e9dbad6fSeschrock */ 2452e9dbad6fSeschrock if (error == 0) { 245391ebeef5Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 2454842727c2SChris Kirby (void) dmu_objset_destroy(zc->zc_name, B_FALSE); 2455e9dbad6fSeschrock } 2456ecd6cf80Smarks nvlist_free(nvprops); 2457fa9e4066Sahrens return (error); 2458fa9e4066Sahrens } 2459fa9e4066Sahrens 24603cb34c60Sahrens /* 24613cb34c60Sahrens * inputs: 24623cb34c60Sahrens * zc_name name of filesystem 24633cb34c60Sahrens * zc_value short name of snapshot 24643cb34c60Sahrens * zc_cookie recursive flag 246514843421SMatthew Ahrens * zc_nvlist_src[_size] property list 24663cb34c60Sahrens * 2467681d9761SEric Taylor * outputs: 2468681d9761SEric Taylor * zc_value short snapname (i.e. part after the '@') 24693cb34c60Sahrens */ 2470fa9e4066Sahrens static int 24711d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 2472fa9e4066Sahrens { 2473bb0ade09Sahrens nvlist_t *nvprops = NULL; 2474bb0ade09Sahrens int error; 2475bb0ade09Sahrens boolean_t recursive = zc->zc_cookie; 2476bb0ade09Sahrens 2477e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 24781d452cf5Sahrens return (EINVAL); 2479bb0ade09Sahrens 2480bb0ade09Sahrens if (zc->zc_nvlist_src != NULL && 2481bb0ade09Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2482478ed9adSEric Taylor zc->zc_iflags, &nvprops)) != 0) 2483bb0ade09Sahrens return (error); 2484bb0ade09Sahrens 2485ea2f5b9eSMatthew Ahrens error = zfs_check_userprops(zc->zc_name, nvprops); 2486ea2f5b9eSMatthew Ahrens if (error) 2487ea2f5b9eSMatthew Ahrens goto out; 2488bb0ade09Sahrens 2489ea2f5b9eSMatthew Ahrens if (nvprops != NULL && nvlist_next_nvpair(nvprops, NULL) != NULL && 2490ea2f5b9eSMatthew Ahrens zfs_earlier_version(zc->zc_name, SPA_VERSION_SNAP_PROPS)) { 2491ea2f5b9eSMatthew Ahrens error = ENOTSUP; 2492ea2f5b9eSMatthew Ahrens goto out; 2493bb0ade09Sahrens } 2494ea2f5b9eSMatthew Ahrens 2495ea2f5b9eSMatthew Ahrens error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, 2496ea2f5b9eSMatthew Ahrens nvprops, recursive); 2497ea2f5b9eSMatthew Ahrens 2498ea2f5b9eSMatthew Ahrens out: 2499bb0ade09Sahrens nvlist_free(nvprops); 2500bb0ade09Sahrens return (error); 25011d452cf5Sahrens } 2502fa9e4066Sahrens 2503cdf5b4caSmmusante int 25041d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 25051d452cf5Sahrens { 25060b69c2f0Sahrens vfs_t *vfsp = NULL; 25071d452cf5Sahrens 2508745cd3c5Smaybee if (arg) { 2509745cd3c5Smaybee char *snapname = arg; 2510745cd3c5Smaybee int len = strlen(name) + strlen(snapname) + 2; 2511745cd3c5Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 25121d452cf5Sahrens 2513745cd3c5Smaybee (void) strcpy(buf, name); 2514745cd3c5Smaybee (void) strcat(buf, "@"); 2515745cd3c5Smaybee (void) strcat(buf, snapname); 2516745cd3c5Smaybee vfsp = zfs_get_vfs(buf); 2517745cd3c5Smaybee kmem_free(buf, len); 25180b69c2f0Sahrens } else if (strchr(name, '@')) { 25191d452cf5Sahrens vfsp = zfs_get_vfs(name); 25201d452cf5Sahrens } 25211d452cf5Sahrens 25221d452cf5Sahrens if (vfsp) { 2523fa9e4066Sahrens /* 25241d452cf5Sahrens * Always force the unmount for snapshots. 2525fa9e4066Sahrens */ 25261d452cf5Sahrens int flag = MS_FORCE; 25271d452cf5Sahrens int err; 25281d452cf5Sahrens 25291d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 2530fa9e4066Sahrens VFS_RELE(vfsp); 25311d452cf5Sahrens return (err); 2532fa9e4066Sahrens } 25331d452cf5Sahrens VFS_RELE(vfsp); 25341d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 25351d452cf5Sahrens return (err); 25361d452cf5Sahrens } 25371d452cf5Sahrens return (0); 25381d452cf5Sahrens } 25391d452cf5Sahrens 25403cb34c60Sahrens /* 25413cb34c60Sahrens * inputs: 2542842727c2SChris Kirby * zc_name name of filesystem 2543842727c2SChris Kirby * zc_value short name of snapshot 2544842727c2SChris Kirby * zc_defer_destroy mark for deferred destroy 25453cb34c60Sahrens * 25463cb34c60Sahrens * outputs: none 25473cb34c60Sahrens */ 25481d452cf5Sahrens static int 25491d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 25501d452cf5Sahrens { 25511d452cf5Sahrens int err; 25521d452cf5Sahrens 2553e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 25541d452cf5Sahrens return (EINVAL); 25551d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 2556e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 25571d452cf5Sahrens if (err) 25581d452cf5Sahrens return (err); 2559842727c2SChris Kirby return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value, 2560842727c2SChris Kirby zc->zc_defer_destroy)); 25611d452cf5Sahrens } 25621d452cf5Sahrens 25633cb34c60Sahrens /* 25643cb34c60Sahrens * inputs: 25653cb34c60Sahrens * zc_name name of dataset to destroy 25663cb34c60Sahrens * zc_objset_type type of objset 2567842727c2SChris Kirby * zc_defer_destroy mark for deferred destroy 25683cb34c60Sahrens * 25693cb34c60Sahrens * outputs: none 25703cb34c60Sahrens */ 25711d452cf5Sahrens static int 25721d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 25731d452cf5Sahrens { 2574681d9761SEric Taylor int err; 25751d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 2576681d9761SEric Taylor err = zfs_unmount_snap(zc->zc_name, NULL); 25771d452cf5Sahrens if (err) 25781d452cf5Sahrens return (err); 2579fa9e4066Sahrens } 2580fa9e4066Sahrens 2581681d9761SEric Taylor err = dmu_objset_destroy(zc->zc_name, zc->zc_defer_destroy); 2582681d9761SEric Taylor if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0) 25835c987a37SChris Kirby (void) zvol_remove_minor(zc->zc_name); 2584681d9761SEric Taylor return (err); 2585fa9e4066Sahrens } 2586fa9e4066Sahrens 25873cb34c60Sahrens /* 25883cb34c60Sahrens * inputs: 25894ccbb6e7Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 25903cb34c60Sahrens * 25913cb34c60Sahrens * outputs: none 25923cb34c60Sahrens */ 2593fa9e4066Sahrens static int 2594fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2595fa9e4066Sahrens { 2596ae46e4c7SMatthew Ahrens dsl_dataset_t *ds, *clone; 25974ccbb6e7Sahrens int error; 2598ae46e4c7SMatthew Ahrens zfsvfs_t *zfsvfs; 2599ae46e4c7SMatthew Ahrens char *clone_name; 2600ae46e4c7SMatthew Ahrens 2601ae46e4c7SMatthew Ahrens error = dsl_dataset_hold(zc->zc_name, FTAG, &ds); 2602ae46e4c7SMatthew Ahrens if (error) 2603ae46e4c7SMatthew Ahrens return (error); 2604ae46e4c7SMatthew Ahrens 2605ae46e4c7SMatthew Ahrens /* must not be a snapshot */ 2606ae46e4c7SMatthew Ahrens if (dsl_dataset_is_snapshot(ds)) { 2607ae46e4c7SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 2608ae46e4c7SMatthew Ahrens return (EINVAL); 2609ae46e4c7SMatthew Ahrens } 2610ae46e4c7SMatthew Ahrens 2611ae46e4c7SMatthew Ahrens /* must have a most recent snapshot */ 2612ae46e4c7SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_txg < TXG_INITIAL) { 2613ae46e4c7SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 2614ae46e4c7SMatthew Ahrens return (EINVAL); 2615ae46e4c7SMatthew Ahrens } 26164ccbb6e7Sahrens 26174ccbb6e7Sahrens /* 2618ae46e4c7SMatthew Ahrens * Create clone of most recent snapshot. 26194ccbb6e7Sahrens */ 2620ae46e4c7SMatthew Ahrens clone_name = kmem_asprintf("%s/%%rollback", zc->zc_name); 2621ae46e4c7SMatthew Ahrens error = dmu_objset_clone(clone_name, ds->ds_prev, DS_FLAG_INCONSISTENT); 26224ccbb6e7Sahrens if (error) 2623ae46e4c7SMatthew Ahrens goto out; 26244ccbb6e7Sahrens 2625503ad85cSMatthew Ahrens error = dsl_dataset_own(clone_name, B_TRUE, FTAG, &clone); 2626ae46e4c7SMatthew Ahrens if (error) 2627ae46e4c7SMatthew Ahrens goto out; 2628ae46e4c7SMatthew Ahrens 2629ae46e4c7SMatthew Ahrens /* 2630ae46e4c7SMatthew Ahrens * Do clone swap. 2631ae46e4c7SMatthew Ahrens */ 263214843421SMatthew Ahrens if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 2633503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 263447f263f4Sek if (error == 0) { 263547f263f4Sek int resume_err; 26364ccbb6e7Sahrens 2637ae46e4c7SMatthew Ahrens if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 2638ae46e4c7SMatthew Ahrens error = dsl_dataset_clone_swap(clone, ds, 2639ae46e4c7SMatthew Ahrens B_TRUE); 2640ae46e4c7SMatthew Ahrens dsl_dataset_disown(ds, FTAG); 2641ae46e4c7SMatthew Ahrens ds = NULL; 2642ae46e4c7SMatthew Ahrens } else { 2643ae46e4c7SMatthew Ahrens error = EBUSY; 2644ae46e4c7SMatthew Ahrens } 2645503ad85cSMatthew Ahrens resume_err = zfs_resume_fs(zfsvfs, zc->zc_name); 264647f263f4Sek error = error ? error : resume_err; 264747f263f4Sek } 26484ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 26494ccbb6e7Sahrens } else { 2650ae46e4c7SMatthew Ahrens if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 2651ae46e4c7SMatthew Ahrens error = dsl_dataset_clone_swap(clone, ds, B_TRUE); 2652ae46e4c7SMatthew Ahrens dsl_dataset_disown(ds, FTAG); 2653ae46e4c7SMatthew Ahrens ds = NULL; 2654ae46e4c7SMatthew Ahrens } else { 2655ae46e4c7SMatthew Ahrens error = EBUSY; 2656ae46e4c7SMatthew Ahrens } 26574ccbb6e7Sahrens } 26584ccbb6e7Sahrens 2659ae46e4c7SMatthew Ahrens /* 2660ae46e4c7SMatthew Ahrens * Destroy clone (which also closes it). 2661ae46e4c7SMatthew Ahrens */ 2662ae46e4c7SMatthew Ahrens (void) dsl_dataset_destroy(clone, FTAG, B_FALSE); 2663ae46e4c7SMatthew Ahrens 2664ae46e4c7SMatthew Ahrens out: 2665ae46e4c7SMatthew Ahrens strfree(clone_name); 2666ae46e4c7SMatthew Ahrens if (ds) 2667ae46e4c7SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 26684ccbb6e7Sahrens return (error); 2669fa9e4066Sahrens } 2670fa9e4066Sahrens 26713cb34c60Sahrens /* 26723cb34c60Sahrens * inputs: 26733cb34c60Sahrens * zc_name old name of dataset 26743cb34c60Sahrens * zc_value new name of dataset 26753cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 26763cb34c60Sahrens * 26773cb34c60Sahrens * outputs: none 26783cb34c60Sahrens */ 2679fa9e4066Sahrens static int 2680fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2681fa9e4066Sahrens { 26827f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 2683cdf5b4caSmmusante 2684e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2685f18faf3fSek if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2686f18faf3fSek strchr(zc->zc_value, '%')) 2687fa9e4066Sahrens return (EINVAL); 2688fa9e4066Sahrens 2689cdf5b4caSmmusante /* 2690cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 2691cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 2692cdf5b4caSmmusante * to unmount. 2693cdf5b4caSmmusante */ 2694cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2695fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 26961d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 26971d452cf5Sahrens if (err) 26981d452cf5Sahrens return (err); 2699fa9e4066Sahrens } 2700681d9761SEric Taylor if (zc->zc_objset_type == DMU_OST_ZVOL) 2701681d9761SEric Taylor (void) zvol_remove_minor(zc->zc_name); 2702cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2703fa9e4066Sahrens } 2704fa9e4066Sahrens 2705745cd3c5Smaybee static void 27066e77af0aSDavid Pacheco clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops) 2707745cd3c5Smaybee { 2708745cd3c5Smaybee zfs_cmd_t *zc; 2709745cd3c5Smaybee nvpair_t *prop; 2710745cd3c5Smaybee 2711745cd3c5Smaybee if (props == NULL) 2712745cd3c5Smaybee return; 2713745cd3c5Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 2714745cd3c5Smaybee (void) strcpy(zc->zc_name, dataset); 2715745cd3c5Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 2716745cd3c5Smaybee prop = nvlist_next_nvpair(props, prop)) { 27176e77af0aSDavid Pacheco if (newprops != NULL && 27186e77af0aSDavid Pacheco nvlist_exists(newprops, nvpair_name(prop))) 27196e77af0aSDavid Pacheco continue; 2720745cd3c5Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 2721745cd3c5Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 2722745cd3c5Smaybee (void) zfs_ioc_inherit_prop(zc); 2723745cd3c5Smaybee } 2724745cd3c5Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 2725745cd3c5Smaybee } 2726745cd3c5Smaybee 27273cb34c60Sahrens /* 27283cb34c60Sahrens * inputs: 27293cb34c60Sahrens * zc_name name of containing filesystem 27303cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 27313cb34c60Sahrens * zc_value name of snapshot to create 27323cb34c60Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 27333cb34c60Sahrens * zc_cookie file descriptor to recv from 27343cb34c60Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 27353cb34c60Sahrens * zc_guid force flag 27363cb34c60Sahrens * 27373cb34c60Sahrens * outputs: 27383cb34c60Sahrens * zc_cookie number of bytes read 27393cb34c60Sahrens */ 2740fa9e4066Sahrens static int 27413cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2742fa9e4066Sahrens { 2743fa9e4066Sahrens file_t *fp; 2744f18faf3fSek objset_t *os; 27453cb34c60Sahrens dmu_recv_cookie_t drc; 2746f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 2747f18faf3fSek int error, fd; 27483cb34c60Sahrens offset_t off; 27493cb34c60Sahrens nvlist_t *props = NULL; 2750745cd3c5Smaybee nvlist_t *origprops = NULL; 27513cb34c60Sahrens objset_t *origin = NULL; 27523cb34c60Sahrens char *tosnap; 27533cb34c60Sahrens char tofs[ZFS_MAXNAMELEN]; 2754fa9e4066Sahrens 27553ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2756f18faf3fSek strchr(zc->zc_value, '@') == NULL || 2757f18faf3fSek strchr(zc->zc_value, '%')) 27583ccfa83cSahrens return (EINVAL); 27593ccfa83cSahrens 27603cb34c60Sahrens (void) strcpy(tofs, zc->zc_value); 27613cb34c60Sahrens tosnap = strchr(tofs, '@'); 27623cb34c60Sahrens *tosnap = '\0'; 27633cb34c60Sahrens tosnap++; 27643cb34c60Sahrens 27653cb34c60Sahrens if (zc->zc_nvlist_src != NULL && 27663cb34c60Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2767478ed9adSEric Taylor zc->zc_iflags, &props)) != 0) 27683cb34c60Sahrens return (error); 27693cb34c60Sahrens 2770fa9e4066Sahrens fd = zc->zc_cookie; 2771fa9e4066Sahrens fp = getf(fd); 27723cb34c60Sahrens if (fp == NULL) { 27733cb34c60Sahrens nvlist_free(props); 2774fa9e4066Sahrens return (EBADF); 27753cb34c60Sahrens } 2776f18faf3fSek 2777503ad85cSMatthew Ahrens if (props && dmu_objset_hold(tofs, FTAG, &os) == 0) { 2778745cd3c5Smaybee /* 2779745cd3c5Smaybee * If new properties are supplied, they are to completely 2780745cd3c5Smaybee * replace the existing ones, so stash away the existing ones. 2781745cd3c5Smaybee */ 2782503ad85cSMatthew Ahrens (void) dsl_prop_get_all(os, &origprops, B_TRUE); 2783745cd3c5Smaybee 2784503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2785f18faf3fSek } 2786f18faf3fSek 27873cb34c60Sahrens if (zc->zc_string[0]) { 2788503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_string, FTAG, &origin); 2789745cd3c5Smaybee if (error) 2790745cd3c5Smaybee goto out; 27913cb34c60Sahrens } 27923cb34c60Sahrens 27933cb34c60Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 2794f4b94bdeSMatthew Ahrens force, origin, &drc); 27953cb34c60Sahrens if (origin) 2796503ad85cSMatthew Ahrens dmu_objset_rele(origin, FTAG); 2797745cd3c5Smaybee if (error) 2798745cd3c5Smaybee goto out; 2799f18faf3fSek 2800f18faf3fSek /* 2801745cd3c5Smaybee * Reset properties. We do this before we receive the stream 2802745cd3c5Smaybee * so that the properties are applied to the new data. 2803f18faf3fSek */ 28043cb34c60Sahrens if (props) { 28056e77af0aSDavid Pacheco clear_props(tofs, origprops, props); 2806745cd3c5Smaybee /* 2807745cd3c5Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 2808745cd3c5Smaybee */ 2809745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, props); 28103cb34c60Sahrens } 28113cb34c60Sahrens 28123cb34c60Sahrens off = fp->f_offset; 28133cb34c60Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 2814a2eea2e1Sahrens 2815f4b94bdeSMatthew Ahrens if (error == 0) { 2816f4b94bdeSMatthew Ahrens zfsvfs_t *zfsvfs = NULL; 2817745cd3c5Smaybee 2818f4b94bdeSMatthew Ahrens if (getzfsvfs(tofs, &zfsvfs) == 0) { 2819f4b94bdeSMatthew Ahrens /* online recv */ 2820f4b94bdeSMatthew Ahrens int end_err; 2821745cd3c5Smaybee 2822503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 2823f4b94bdeSMatthew Ahrens /* 2824f4b94bdeSMatthew Ahrens * If the suspend fails, then the recv_end will 2825f4b94bdeSMatthew Ahrens * likely also fail, and clean up after itself. 2826f4b94bdeSMatthew Ahrens */ 2827f4b94bdeSMatthew Ahrens end_err = dmu_recv_end(&drc); 2828f4b94bdeSMatthew Ahrens if (error == 0) { 2829f4b94bdeSMatthew Ahrens int resume_err = 2830503ad85cSMatthew Ahrens zfs_resume_fs(zfsvfs, tofs); 2831f4b94bdeSMatthew Ahrens error = error ? error : resume_err; 2832f4b94bdeSMatthew Ahrens } 2833f4b94bdeSMatthew Ahrens error = error ? error : end_err; 2834f4b94bdeSMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 2835745cd3c5Smaybee } else { 2836f4b94bdeSMatthew Ahrens error = dmu_recv_end(&drc); 28373cb34c60Sahrens } 283847f263f4Sek } 28393cb34c60Sahrens 28403cb34c60Sahrens zc->zc_cookie = off - fp->f_offset; 28413cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 28423cb34c60Sahrens fp->f_offset = off; 2843a2eea2e1Sahrens 2844745cd3c5Smaybee /* 2845745cd3c5Smaybee * On error, restore the original props. 2846745cd3c5Smaybee */ 2847745cd3c5Smaybee if (error && props) { 28486e77af0aSDavid Pacheco clear_props(tofs, props, NULL); 2849745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 2850745cd3c5Smaybee } 2851745cd3c5Smaybee out: 2852745cd3c5Smaybee nvlist_free(props); 2853745cd3c5Smaybee nvlist_free(origprops); 2854fa9e4066Sahrens releasef(fd); 2855fa9e4066Sahrens return (error); 2856fa9e4066Sahrens } 2857fa9e4066Sahrens 28583cb34c60Sahrens /* 28593cb34c60Sahrens * inputs: 28603cb34c60Sahrens * zc_name name of snapshot to send 28613cb34c60Sahrens * zc_value short name of incremental fromsnap (may be empty) 28623cb34c60Sahrens * zc_cookie file descriptor to send stream to 28633cb34c60Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 28643cb34c60Sahrens * 28653cb34c60Sahrens * outputs: none 28663cb34c60Sahrens */ 2867fa9e4066Sahrens static int 28683cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2869fa9e4066Sahrens { 2870fa9e4066Sahrens objset_t *fromsnap = NULL; 2871fa9e4066Sahrens objset_t *tosnap; 2872fa9e4066Sahrens file_t *fp; 2873fa9e4066Sahrens int error; 28743cb34c60Sahrens offset_t off; 2875fa9e4066Sahrens 2876503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &tosnap); 2877fa9e4066Sahrens if (error) 2878fa9e4066Sahrens return (error); 2879fa9e4066Sahrens 2880e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 28816a0f0066SEric Taylor char *buf; 2882a2eea2e1Sahrens char *cp; 2883a2eea2e1Sahrens 28846a0f0066SEric Taylor buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 28856a0f0066SEric Taylor (void) strncpy(buf, zc->zc_name, MAXPATHLEN); 2886a2eea2e1Sahrens cp = strchr(buf, '@'); 2887a2eea2e1Sahrens if (cp) 2888a2eea2e1Sahrens *(cp+1) = 0; 28896a0f0066SEric Taylor (void) strncat(buf, zc->zc_value, MAXPATHLEN); 2890503ad85cSMatthew Ahrens error = dmu_objset_hold(buf, FTAG, &fromsnap); 28916a0f0066SEric Taylor kmem_free(buf, MAXPATHLEN); 2892fa9e4066Sahrens if (error) { 2893503ad85cSMatthew Ahrens dmu_objset_rele(tosnap, FTAG); 2894fa9e4066Sahrens return (error); 2895fa9e4066Sahrens } 2896fa9e4066Sahrens } 2897fa9e4066Sahrens 2898fa9e4066Sahrens fp = getf(zc->zc_cookie); 2899fa9e4066Sahrens if (fp == NULL) { 2900503ad85cSMatthew Ahrens dmu_objset_rele(tosnap, FTAG); 2901fa9e4066Sahrens if (fromsnap) 2902503ad85cSMatthew Ahrens dmu_objset_rele(fromsnap, FTAG); 2903fa9e4066Sahrens return (EBADF); 2904fa9e4066Sahrens } 2905fa9e4066Sahrens 29063cb34c60Sahrens off = fp->f_offset; 29073cb34c60Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 2908fa9e4066Sahrens 29093cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 29103cb34c60Sahrens fp->f_offset = off; 2911fa9e4066Sahrens releasef(zc->zc_cookie); 2912fa9e4066Sahrens if (fromsnap) 2913503ad85cSMatthew Ahrens dmu_objset_rele(fromsnap, FTAG); 2914503ad85cSMatthew Ahrens dmu_objset_rele(tosnap, FTAG); 2915fa9e4066Sahrens return (error); 2916fa9e4066Sahrens } 2917fa9e4066Sahrens 2918ea8dc4b6Seschrock static int 2919ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 2920ea8dc4b6Seschrock { 2921ea8dc4b6Seschrock int id, error; 2922ea8dc4b6Seschrock 2923ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2924ea8dc4b6Seschrock &zc->zc_inject_record); 2925ea8dc4b6Seschrock 2926ea8dc4b6Seschrock if (error == 0) 2927ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 2928ea8dc4b6Seschrock 2929ea8dc4b6Seschrock return (error); 2930ea8dc4b6Seschrock } 2931ea8dc4b6Seschrock 2932ea8dc4b6Seschrock static int 2933ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 2934ea8dc4b6Seschrock { 2935ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 2936ea8dc4b6Seschrock } 2937ea8dc4b6Seschrock 2938ea8dc4b6Seschrock static int 2939ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2940ea8dc4b6Seschrock { 2941ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2942ea8dc4b6Seschrock int error; 2943ea8dc4b6Seschrock 2944ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2945ea8dc4b6Seschrock &zc->zc_inject_record); 2946ea8dc4b6Seschrock 2947ea8dc4b6Seschrock zc->zc_guid = id; 2948ea8dc4b6Seschrock 2949ea8dc4b6Seschrock return (error); 2950ea8dc4b6Seschrock } 2951ea8dc4b6Seschrock 2952ea8dc4b6Seschrock static int 2953ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2954ea8dc4b6Seschrock { 2955ea8dc4b6Seschrock spa_t *spa; 2956ea8dc4b6Seschrock int error; 2957e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2958ea8dc4b6Seschrock 2959ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2960ea8dc4b6Seschrock return (error); 2961ea8dc4b6Seschrock 2962e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2963ea8dc4b6Seschrock &count); 2964ea8dc4b6Seschrock if (error == 0) 2965e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2966ea8dc4b6Seschrock else 2967e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2968ea8dc4b6Seschrock 2969ea8dc4b6Seschrock spa_close(spa, FTAG); 2970ea8dc4b6Seschrock 2971ea8dc4b6Seschrock return (error); 2972ea8dc4b6Seschrock } 2973ea8dc4b6Seschrock 2974ea8dc4b6Seschrock static int 2975ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2976ea8dc4b6Seschrock { 2977ea8dc4b6Seschrock spa_t *spa; 2978ea8dc4b6Seschrock vdev_t *vd; 2979bb8b5132Sek int error; 2980ea8dc4b6Seschrock 2981b87f3af3Sperrin /* 2982b87f3af3Sperrin * On zpool clear we also fix up missing slogs 2983b87f3af3Sperrin */ 2984b87f3af3Sperrin mutex_enter(&spa_namespace_lock); 2985b87f3af3Sperrin spa = spa_lookup(zc->zc_name); 2986b87f3af3Sperrin if (spa == NULL) { 2987b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 2988b87f3af3Sperrin return (EIO); 2989b87f3af3Sperrin } 2990*b24ab676SJeff Bonwick if (spa_get_log_state(spa) == SPA_LOG_MISSING) { 2991b87f3af3Sperrin /* we need to let spa_open/spa_load clear the chains */ 2992*b24ab676SJeff Bonwick spa_set_log_state(spa, SPA_LOG_CLEAR); 2993b87f3af3Sperrin } 2994468c413aSTim Haley spa->spa_last_open_failed = 0; 2995b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 2996b87f3af3Sperrin 2997468c413aSTim Haley if (zc->zc_cookie == ZPOOL_NO_REWIND) { 2998468c413aSTim Haley error = spa_open(zc->zc_name, &spa, FTAG); 2999468c413aSTim Haley } else { 3000468c413aSTim Haley nvlist_t *policy; 3001468c413aSTim Haley nvlist_t *config = NULL; 3002468c413aSTim Haley 3003468c413aSTim Haley if (zc->zc_nvlist_src == NULL) 3004468c413aSTim Haley return (EINVAL); 3005468c413aSTim Haley 3006468c413aSTim Haley if ((error = get_nvlist(zc->zc_nvlist_src, 3007468c413aSTim Haley zc->zc_nvlist_src_size, zc->zc_iflags, &policy)) == 0) { 3008468c413aSTim Haley error = spa_open_rewind(zc->zc_name, &spa, FTAG, 3009468c413aSTim Haley policy, &config); 3010468c413aSTim Haley if (config != NULL) { 3011468c413aSTim Haley (void) put_nvlist(zc, config); 3012468c413aSTim Haley nvlist_free(config); 3013468c413aSTim Haley } 3014468c413aSTim Haley nvlist_free(policy); 3015468c413aSTim Haley } 3016468c413aSTim Haley } 3017468c413aSTim Haley 3018468c413aSTim Haley if (error) 3019ea8dc4b6Seschrock return (error); 3020ea8dc4b6Seschrock 30218f18d1faSGeorge Wilson spa_vdev_state_enter(spa, SCL_NONE); 3022ea8dc4b6Seschrock 3023e9dbad6fSeschrock if (zc->zc_guid == 0) { 3024ea8dc4b6Seschrock vd = NULL; 3025c5904d13Seschrock } else { 3026c5904d13Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 3027fa94a07fSbrendan if (vd == NULL) { 3028e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, ENODEV); 3029fa94a07fSbrendan spa_close(spa, FTAG); 3030fa94a07fSbrendan return (ENODEV); 3031fa94a07fSbrendan } 3032ea8dc4b6Seschrock } 3033ea8dc4b6Seschrock 3034e14bb325SJeff Bonwick vdev_clear(spa, vd); 3035e14bb325SJeff Bonwick 3036e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, 0); 3037ea8dc4b6Seschrock 3038e14bb325SJeff Bonwick /* 3039e14bb325SJeff Bonwick * Resume any suspended I/Os. 3040e14bb325SJeff Bonwick */ 304154d692b7SGeorge Wilson if (zio_resume(spa) != 0) 304254d692b7SGeorge Wilson error = EIO; 3043ea8dc4b6Seschrock 3044ea8dc4b6Seschrock spa_close(spa, FTAG); 3045ea8dc4b6Seschrock 304654d692b7SGeorge Wilson return (error); 3047ea8dc4b6Seschrock } 3048ea8dc4b6Seschrock 30493cb34c60Sahrens /* 30503cb34c60Sahrens * inputs: 30513cb34c60Sahrens * zc_name name of filesystem 30523cb34c60Sahrens * zc_value name of origin snapshot 30533cb34c60Sahrens * 3054681d9761SEric Taylor * outputs: 3055681d9761SEric Taylor * zc_string name of conflicting snapshot, if there is one 30563cb34c60Sahrens */ 305799653d4eSeschrock static int 305899653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 305999653d4eSeschrock { 30600b69c2f0Sahrens char *cp; 30610b69c2f0Sahrens 30620b69c2f0Sahrens /* 30630b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 30640b69c2f0Sahrens * it's easier. 30650b69c2f0Sahrens */ 3066e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 30670b69c2f0Sahrens if (cp) 30680b69c2f0Sahrens *cp = '\0'; 3069e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 30700b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 3071681d9761SEric Taylor return (dsl_dataset_promote(zc->zc_name, zc->zc_string)); 307299653d4eSeschrock } 307399653d4eSeschrock 307414843421SMatthew Ahrens /* 307514843421SMatthew Ahrens * Retrieve a single {user|group}{used|quota}@... property. 307614843421SMatthew Ahrens * 307714843421SMatthew Ahrens * inputs: 307814843421SMatthew Ahrens * zc_name name of filesystem 307914843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 308014843421SMatthew Ahrens * zc_value domain name (eg. "S-1-234-567-89") 308114843421SMatthew Ahrens * zc_guid RID/UID/GID 308214843421SMatthew Ahrens * 308314843421SMatthew Ahrens * outputs: 308414843421SMatthew Ahrens * zc_cookie property value 308514843421SMatthew Ahrens */ 308614843421SMatthew Ahrens static int 308714843421SMatthew Ahrens zfs_ioc_userspace_one(zfs_cmd_t *zc) 308814843421SMatthew Ahrens { 308914843421SMatthew Ahrens zfsvfs_t *zfsvfs; 309014843421SMatthew Ahrens int error; 309114843421SMatthew Ahrens 309214843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 309314843421SMatthew Ahrens return (EINVAL); 309414843421SMatthew Ahrens 3095503ad85cSMatthew Ahrens error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs); 309614843421SMatthew Ahrens if (error) 309714843421SMatthew Ahrens return (error); 309814843421SMatthew Ahrens 309914843421SMatthew Ahrens error = zfs_userspace_one(zfsvfs, 310014843421SMatthew Ahrens zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 310114843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 310214843421SMatthew Ahrens 310314843421SMatthew Ahrens return (error); 310414843421SMatthew Ahrens } 310514843421SMatthew Ahrens 310614843421SMatthew Ahrens /* 310714843421SMatthew Ahrens * inputs: 310814843421SMatthew Ahrens * zc_name name of filesystem 310914843421SMatthew Ahrens * zc_cookie zap cursor 311014843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 311114843421SMatthew Ahrens * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 311214843421SMatthew Ahrens * 311314843421SMatthew Ahrens * outputs: 311414843421SMatthew Ahrens * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 311514843421SMatthew Ahrens * zc_cookie zap cursor 311614843421SMatthew Ahrens */ 311714843421SMatthew Ahrens static int 311814843421SMatthew Ahrens zfs_ioc_userspace_many(zfs_cmd_t *zc) 311914843421SMatthew Ahrens { 312014843421SMatthew Ahrens zfsvfs_t *zfsvfs; 312114843421SMatthew Ahrens int error; 312214843421SMatthew Ahrens 3123503ad85cSMatthew Ahrens error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs); 312414843421SMatthew Ahrens if (error) 312514843421SMatthew Ahrens return (error); 312614843421SMatthew Ahrens 312714843421SMatthew Ahrens int bufsize = zc->zc_nvlist_dst_size; 312814843421SMatthew Ahrens void *buf = kmem_alloc(bufsize, KM_SLEEP); 312914843421SMatthew Ahrens 313014843421SMatthew Ahrens error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 313114843421SMatthew Ahrens buf, &zc->zc_nvlist_dst_size); 313214843421SMatthew Ahrens 313314843421SMatthew Ahrens if (error == 0) { 313414843421SMatthew Ahrens error = xcopyout(buf, 313514843421SMatthew Ahrens (void *)(uintptr_t)zc->zc_nvlist_dst, 313614843421SMatthew Ahrens zc->zc_nvlist_dst_size); 313714843421SMatthew Ahrens } 313814843421SMatthew Ahrens kmem_free(buf, bufsize); 313914843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 314014843421SMatthew Ahrens 314114843421SMatthew Ahrens return (error); 314214843421SMatthew Ahrens } 314314843421SMatthew Ahrens 314414843421SMatthew Ahrens /* 314514843421SMatthew Ahrens * inputs: 314614843421SMatthew Ahrens * zc_name name of filesystem 314714843421SMatthew Ahrens * 314814843421SMatthew Ahrens * outputs: 314914843421SMatthew Ahrens * none 315014843421SMatthew Ahrens */ 315114843421SMatthew Ahrens static int 315214843421SMatthew Ahrens zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 315314843421SMatthew Ahrens { 315414843421SMatthew Ahrens objset_t *os; 315514843421SMatthew Ahrens int error; 315614843421SMatthew Ahrens zfsvfs_t *zfsvfs; 315714843421SMatthew Ahrens 315814843421SMatthew Ahrens if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 3159503ad85cSMatthew Ahrens if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { 316014843421SMatthew Ahrens /* 316114843421SMatthew Ahrens * If userused is not enabled, it may be because the 316214843421SMatthew Ahrens * objset needs to be closed & reopened (to grow the 316314843421SMatthew Ahrens * objset_phys_t). Suspend/resume the fs will do that. 316414843421SMatthew Ahrens */ 3165503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 3166503ad85cSMatthew Ahrens if (error == 0) 3167503ad85cSMatthew Ahrens error = zfs_resume_fs(zfsvfs, zc->zc_name); 316814843421SMatthew Ahrens } 316914843421SMatthew Ahrens if (error == 0) 317014843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 317114843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 317214843421SMatthew Ahrens } else { 3173503ad85cSMatthew Ahrens /* XXX kind of reading contents without owning */ 3174503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &os); 317514843421SMatthew Ahrens if (error) 317614843421SMatthew Ahrens return (error); 317714843421SMatthew Ahrens 317814843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(os); 3179503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 318014843421SMatthew Ahrens } 318114843421SMatthew Ahrens 318214843421SMatthew Ahrens return (error); 318314843421SMatthew Ahrens } 318414843421SMatthew Ahrens 3185ecd6cf80Smarks /* 3186ecd6cf80Smarks * We don't want to have a hard dependency 3187ecd6cf80Smarks * against some special symbols in sharefs 3188da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 3189ecd6cf80Smarks * the first file system is shared. 3190da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 3191ecd6cf80Smarks */ 3192da6c28aaSamw int (*znfsexport_fs)(void *arg); 3193ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 3194da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 3195da6c28aaSamw 3196da6c28aaSamw int zfs_nfsshare_inited; 3197da6c28aaSamw int zfs_smbshare_inited; 3198ecd6cf80Smarks 3199ecd6cf80Smarks ddi_modhandle_t nfs_mod; 3200ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 3201da6c28aaSamw ddi_modhandle_t smbsrv_mod; 3202ecd6cf80Smarks kmutex_t zfs_share_lock; 3203ecd6cf80Smarks 3204da6c28aaSamw static int 3205da6c28aaSamw zfs_init_sharefs() 3206da6c28aaSamw { 3207da6c28aaSamw int error; 3208da6c28aaSamw 3209da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 3210da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 3211da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 3212da6c28aaSamw ddi_modopen("fs/sharefs", 3213da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 3214da6c28aaSamw return (ENOSYS); 3215da6c28aaSamw } 3216da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 3217da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 3218da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 3219da6c28aaSamw return (ENOSYS); 3220da6c28aaSamw } 3221da6c28aaSamw return (0); 3222da6c28aaSamw } 3223da6c28aaSamw 3224ecd6cf80Smarks static int 3225ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 3226ecd6cf80Smarks { 3227ecd6cf80Smarks int error; 3228ecd6cf80Smarks int opcode; 3229ecd6cf80Smarks 3230da6c28aaSamw switch (zc->zc_share.z_sharetype) { 3231da6c28aaSamw case ZFS_SHARE_NFS: 3232da6c28aaSamw case ZFS_UNSHARE_NFS: 3233da6c28aaSamw if (zfs_nfsshare_inited == 0) { 3234da6c28aaSamw mutex_enter(&zfs_share_lock); 3235da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 3236da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 3237da6c28aaSamw mutex_exit(&zfs_share_lock); 3238da6c28aaSamw return (ENOSYS); 3239da6c28aaSamw } 3240da6c28aaSamw if (znfsexport_fs == NULL && 3241da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 3242da6c28aaSamw ddi_modsym(nfs_mod, 3243da6c28aaSamw "nfs_export", &error)) == NULL)) { 3244da6c28aaSamw mutex_exit(&zfs_share_lock); 3245da6c28aaSamw return (ENOSYS); 3246da6c28aaSamw } 3247da6c28aaSamw error = zfs_init_sharefs(); 3248da6c28aaSamw if (error) { 3249da6c28aaSamw mutex_exit(&zfs_share_lock); 3250da6c28aaSamw return (ENOSYS); 3251da6c28aaSamw } 3252da6c28aaSamw zfs_nfsshare_inited = 1; 3253ecd6cf80Smarks mutex_exit(&zfs_share_lock); 3254ecd6cf80Smarks } 3255da6c28aaSamw break; 3256da6c28aaSamw case ZFS_SHARE_SMB: 3257da6c28aaSamw case ZFS_UNSHARE_SMB: 3258da6c28aaSamw if (zfs_smbshare_inited == 0) { 3259da6c28aaSamw mutex_enter(&zfs_share_lock); 3260da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 3261da6c28aaSamw ddi_modopen("drv/smbsrv", 3262da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 3263da6c28aaSamw mutex_exit(&zfs_share_lock); 3264da6c28aaSamw return (ENOSYS); 3265da6c28aaSamw } 3266da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 3267da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 3268faa1795aSjb "smb_server_share", &error)) == NULL)) { 3269da6c28aaSamw mutex_exit(&zfs_share_lock); 3270da6c28aaSamw return (ENOSYS); 3271da6c28aaSamw } 3272da6c28aaSamw error = zfs_init_sharefs(); 3273da6c28aaSamw if (error) { 3274da6c28aaSamw mutex_exit(&zfs_share_lock); 3275da6c28aaSamw return (ENOSYS); 3276da6c28aaSamw } 3277da6c28aaSamw zfs_smbshare_inited = 1; 3278ecd6cf80Smarks mutex_exit(&zfs_share_lock); 3279ecd6cf80Smarks } 3280da6c28aaSamw break; 3281da6c28aaSamw default: 3282da6c28aaSamw return (EINVAL); 3283da6c28aaSamw } 3284ecd6cf80Smarks 3285da6c28aaSamw switch (zc->zc_share.z_sharetype) { 3286da6c28aaSamw case ZFS_SHARE_NFS: 3287da6c28aaSamw case ZFS_UNSHARE_NFS: 3288da6c28aaSamw if (error = 3289da6c28aaSamw znfsexport_fs((void *) 3290da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 3291da6c28aaSamw return (error); 3292da6c28aaSamw break; 3293da6c28aaSamw case ZFS_SHARE_SMB: 3294da6c28aaSamw case ZFS_UNSHARE_SMB: 3295da6c28aaSamw if (error = zsmbexport_fs((void *) 3296da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 3297da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 3298743a77edSAlan Wright B_TRUE: B_FALSE)) { 3299da6c28aaSamw return (error); 3300ecd6cf80Smarks } 3301da6c28aaSamw break; 3302ecd6cf80Smarks } 3303ecd6cf80Smarks 3304da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 3305da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 3306ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 3307ecd6cf80Smarks 3308da6c28aaSamw /* 3309da6c28aaSamw * Add or remove share from sharetab 3310da6c28aaSamw */ 3311ecd6cf80Smarks error = zshare_fs(opcode, 3312ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 3313ecd6cf80Smarks zc->zc_share.z_sharemax); 3314ecd6cf80Smarks 3315ecd6cf80Smarks return (error); 3316ecd6cf80Smarks 3317ecd6cf80Smarks } 3318ecd6cf80Smarks 3319743a77edSAlan Wright ace_t full_access[] = { 3320743a77edSAlan Wright {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 3321743a77edSAlan Wright }; 3322743a77edSAlan Wright 3323743a77edSAlan Wright /* 3324743a77edSAlan Wright * Remove all ACL files in shares dir 3325743a77edSAlan Wright */ 3326743a77edSAlan Wright static int 3327743a77edSAlan Wright zfs_smb_acl_purge(znode_t *dzp) 3328743a77edSAlan Wright { 3329743a77edSAlan Wright zap_cursor_t zc; 3330743a77edSAlan Wright zap_attribute_t zap; 3331743a77edSAlan Wright zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 3332743a77edSAlan Wright int error; 3333743a77edSAlan Wright 3334743a77edSAlan Wright for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 3335743a77edSAlan Wright (error = zap_cursor_retrieve(&zc, &zap)) == 0; 3336743a77edSAlan Wright zap_cursor_advance(&zc)) { 3337743a77edSAlan Wright if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 3338743a77edSAlan Wright NULL, 0)) != 0) 3339743a77edSAlan Wright break; 3340743a77edSAlan Wright } 3341743a77edSAlan Wright zap_cursor_fini(&zc); 3342743a77edSAlan Wright return (error); 3343743a77edSAlan Wright } 3344743a77edSAlan Wright 3345743a77edSAlan Wright static int 3346743a77edSAlan Wright zfs_ioc_smb_acl(zfs_cmd_t *zc) 3347743a77edSAlan Wright { 3348743a77edSAlan Wright vnode_t *vp; 3349743a77edSAlan Wright znode_t *dzp; 3350743a77edSAlan Wright vnode_t *resourcevp = NULL; 3351743a77edSAlan Wright znode_t *sharedir; 3352743a77edSAlan Wright zfsvfs_t *zfsvfs; 3353743a77edSAlan Wright nvlist_t *nvlist; 3354743a77edSAlan Wright char *src, *target; 3355743a77edSAlan Wright vattr_t vattr; 3356743a77edSAlan Wright vsecattr_t vsec; 3357743a77edSAlan Wright int error = 0; 3358743a77edSAlan Wright 3359743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 3360743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 3361743a77edSAlan Wright return (error); 3362743a77edSAlan Wright 3363743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 3364743a77edSAlan Wright 3365743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 3366743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 3367743a77edSAlan Wright zc->zc_name) != 0)) { 3368743a77edSAlan Wright VN_RELE(vp); 3369743a77edSAlan Wright return (EINVAL); 3370743a77edSAlan Wright } 3371743a77edSAlan Wright 3372743a77edSAlan Wright dzp = VTOZ(vp); 3373743a77edSAlan Wright zfsvfs = dzp->z_zfsvfs; 3374743a77edSAlan Wright ZFS_ENTER(zfsvfs); 3375743a77edSAlan Wright 33769e1320c0SMark Shellenbaum /* 33779e1320c0SMark Shellenbaum * Create share dir if its missing. 33789e1320c0SMark Shellenbaum */ 33799e1320c0SMark Shellenbaum mutex_enter(&zfsvfs->z_lock); 33809e1320c0SMark Shellenbaum if (zfsvfs->z_shares_dir == 0) { 33819e1320c0SMark Shellenbaum dmu_tx_t *tx; 33829e1320c0SMark Shellenbaum 33839e1320c0SMark Shellenbaum tx = dmu_tx_create(zfsvfs->z_os); 33849e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 33859e1320c0SMark Shellenbaum ZFS_SHARES_DIR); 33869e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 33879e1320c0SMark Shellenbaum error = dmu_tx_assign(tx, TXG_WAIT); 33889e1320c0SMark Shellenbaum if (error) { 33899e1320c0SMark Shellenbaum dmu_tx_abort(tx); 33909e1320c0SMark Shellenbaum } else { 33919e1320c0SMark Shellenbaum error = zfs_create_share_dir(zfsvfs, tx); 33929e1320c0SMark Shellenbaum dmu_tx_commit(tx); 33939e1320c0SMark Shellenbaum } 33949e1320c0SMark Shellenbaum if (error) { 33959e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 33969e1320c0SMark Shellenbaum VN_RELE(vp); 33979e1320c0SMark Shellenbaum ZFS_EXIT(zfsvfs); 33989e1320c0SMark Shellenbaum return (error); 33999e1320c0SMark Shellenbaum } 34009e1320c0SMark Shellenbaum } 34019e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 34029e1320c0SMark Shellenbaum 34039e1320c0SMark Shellenbaum ASSERT(zfsvfs->z_shares_dir); 3404743a77edSAlan Wright if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 34059e1320c0SMark Shellenbaum VN_RELE(vp); 3406743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3407743a77edSAlan Wright return (error); 3408743a77edSAlan Wright } 3409743a77edSAlan Wright 3410743a77edSAlan Wright switch (zc->zc_cookie) { 3411743a77edSAlan Wright case ZFS_SMB_ACL_ADD: 3412743a77edSAlan Wright vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 3413743a77edSAlan Wright vattr.va_type = VREG; 3414743a77edSAlan Wright vattr.va_mode = S_IFREG|0777; 3415743a77edSAlan Wright vattr.va_uid = 0; 3416743a77edSAlan Wright vattr.va_gid = 0; 3417743a77edSAlan Wright 3418743a77edSAlan Wright vsec.vsa_mask = VSA_ACE; 3419743a77edSAlan Wright vsec.vsa_aclentp = &full_access; 3420743a77edSAlan Wright vsec.vsa_aclentsz = sizeof (full_access); 3421743a77edSAlan Wright vsec.vsa_aclcnt = 1; 3422743a77edSAlan Wright 3423743a77edSAlan Wright error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 3424743a77edSAlan Wright &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 3425743a77edSAlan Wright if (resourcevp) 3426743a77edSAlan Wright VN_RELE(resourcevp); 3427743a77edSAlan Wright break; 3428743a77edSAlan Wright 3429743a77edSAlan Wright case ZFS_SMB_ACL_REMOVE: 3430743a77edSAlan Wright error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 3431743a77edSAlan Wright NULL, 0); 3432743a77edSAlan Wright break; 3433743a77edSAlan Wright 3434743a77edSAlan Wright case ZFS_SMB_ACL_RENAME: 3435743a77edSAlan Wright if ((error = get_nvlist(zc->zc_nvlist_src, 3436478ed9adSEric Taylor zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { 3437743a77edSAlan Wright VN_RELE(vp); 3438743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3439743a77edSAlan Wright return (error); 3440743a77edSAlan Wright } 3441743a77edSAlan Wright if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 3442743a77edSAlan Wright nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 3443743a77edSAlan Wright &target)) { 3444743a77edSAlan Wright VN_RELE(vp); 344589459e17SMark Shellenbaum VN_RELE(ZTOV(sharedir)); 3446743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3447743a77edSAlan Wright return (error); 3448743a77edSAlan Wright } 3449743a77edSAlan Wright error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 3450743a77edSAlan Wright kcred, NULL, 0); 3451743a77edSAlan Wright nvlist_free(nvlist); 3452743a77edSAlan Wright break; 3453743a77edSAlan Wright 3454743a77edSAlan Wright case ZFS_SMB_ACL_PURGE: 3455743a77edSAlan Wright error = zfs_smb_acl_purge(sharedir); 3456743a77edSAlan Wright break; 3457743a77edSAlan Wright 3458743a77edSAlan Wright default: 3459743a77edSAlan Wright error = EINVAL; 3460743a77edSAlan Wright break; 3461743a77edSAlan Wright } 3462743a77edSAlan Wright 3463743a77edSAlan Wright VN_RELE(vp); 3464743a77edSAlan Wright VN_RELE(ZTOV(sharedir)); 3465743a77edSAlan Wright 3466743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3467743a77edSAlan Wright 3468743a77edSAlan Wright return (error); 3469743a77edSAlan Wright } 3470743a77edSAlan Wright 3471842727c2SChris Kirby /* 3472842727c2SChris Kirby * inputs: 3473842727c2SChris Kirby * zc_name name of filesystem 3474842727c2SChris Kirby * zc_value short name of snap 3475842727c2SChris Kirby * zc_string user-supplied tag for this reference 3476842727c2SChris Kirby * zc_cookie recursive flag 3477ca45db41SChris Kirby * zc_temphold set if hold is temporary 3478842727c2SChris Kirby * 3479842727c2SChris Kirby * outputs: none 3480842727c2SChris Kirby */ 3481842727c2SChris Kirby static int 3482842727c2SChris Kirby zfs_ioc_hold(zfs_cmd_t *zc) 3483842727c2SChris Kirby { 3484842727c2SChris Kirby boolean_t recursive = zc->zc_cookie; 3485842727c2SChris Kirby 3486842727c2SChris Kirby if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 3487842727c2SChris Kirby return (EINVAL); 3488842727c2SChris Kirby 3489842727c2SChris Kirby return (dsl_dataset_user_hold(zc->zc_name, zc->zc_value, 3490ca45db41SChris Kirby zc->zc_string, recursive, zc->zc_temphold)); 3491842727c2SChris Kirby } 3492842727c2SChris Kirby 3493842727c2SChris Kirby /* 3494842727c2SChris Kirby * inputs: 3495842727c2SChris Kirby * zc_name name of dataset from which we're releasing a user reference 3496842727c2SChris Kirby * zc_value short name of snap 3497842727c2SChris Kirby * zc_string user-supplied tag for this reference 3498842727c2SChris Kirby * zc_cookie recursive flag 3499842727c2SChris Kirby * 3500842727c2SChris Kirby * outputs: none 3501842727c2SChris Kirby */ 3502842727c2SChris Kirby static int 3503842727c2SChris Kirby zfs_ioc_release(zfs_cmd_t *zc) 3504842727c2SChris Kirby { 3505842727c2SChris Kirby boolean_t recursive = zc->zc_cookie; 3506842727c2SChris Kirby 3507842727c2SChris Kirby if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 3508842727c2SChris Kirby return (EINVAL); 3509842727c2SChris Kirby 3510842727c2SChris Kirby return (dsl_dataset_user_release(zc->zc_name, zc->zc_value, 3511842727c2SChris Kirby zc->zc_string, recursive)); 3512842727c2SChris Kirby } 3513842727c2SChris Kirby 3514842727c2SChris Kirby /* 3515842727c2SChris Kirby * inputs: 3516842727c2SChris Kirby * zc_name name of filesystem 3517842727c2SChris Kirby * 3518842727c2SChris Kirby * outputs: 3519842727c2SChris Kirby * zc_nvlist_src{_size} nvlist of snapshot holds 3520842727c2SChris Kirby */ 3521842727c2SChris Kirby static int 3522842727c2SChris Kirby zfs_ioc_get_holds(zfs_cmd_t *zc) 3523842727c2SChris Kirby { 3524842727c2SChris Kirby nvlist_t *nvp; 3525842727c2SChris Kirby int error; 3526842727c2SChris Kirby 3527842727c2SChris Kirby if ((error = dsl_dataset_get_holds(zc->zc_name, &nvp)) == 0) { 3528842727c2SChris Kirby error = put_nvlist(zc, nvp); 3529842727c2SChris Kirby nvlist_free(nvp); 3530842727c2SChris Kirby } 3531842727c2SChris Kirby 3532842727c2SChris Kirby return (error); 3533842727c2SChris Kirby } 3534842727c2SChris Kirby 3535ecd6cf80Smarks /* 35362a6b87f0Sek * pool create, destroy, and export don't log the history as part of 35372a6b87f0Sek * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 35382a6b87f0Sek * do the logging of those commands. 3539ecd6cf80Smarks */ 3540fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 354154d692b7SGeorge Wilson { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE, 354254d692b7SGeorge Wilson B_FALSE }, 354354d692b7SGeorge Wilson { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE, 354454d692b7SGeorge Wilson B_FALSE }, 354554d692b7SGeorge Wilson { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE, 354654d692b7SGeorge Wilson B_FALSE }, 354754d692b7SGeorge Wilson { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE, 354854d692b7SGeorge Wilson B_FALSE }, 354954d692b7SGeorge Wilson { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE, 355054d692b7SGeorge Wilson B_FALSE }, 355154d692b7SGeorge Wilson { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE, 355254d692b7SGeorge Wilson B_FALSE }, 355354d692b7SGeorge Wilson { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE, 355454d692b7SGeorge Wilson B_FALSE }, 355554d692b7SGeorge Wilson { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE, 355654d692b7SGeorge Wilson B_TRUE }, 355754d692b7SGeorge Wilson { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, 355854d692b7SGeorge Wilson B_FALSE }, 355954d692b7SGeorge Wilson { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE, 356054d692b7SGeorge Wilson B_TRUE }, 356154d692b7SGeorge Wilson { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE, 356254d692b7SGeorge Wilson B_FALSE }, 356354d692b7SGeorge Wilson { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE, 356454d692b7SGeorge Wilson B_TRUE }, 356554d692b7SGeorge Wilson { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE, 356654d692b7SGeorge Wilson B_TRUE }, 356754d692b7SGeorge Wilson { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE, 356854d692b7SGeorge Wilson B_FALSE }, 356954d692b7SGeorge Wilson { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 357054d692b7SGeorge Wilson B_TRUE }, 357154d692b7SGeorge Wilson { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 357254d692b7SGeorge Wilson B_TRUE }, 357354d692b7SGeorge Wilson { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE, 357454d692b7SGeorge Wilson B_TRUE }, 35756809eb4eSEric Schrock { zfs_ioc_vdev_setfru, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35766809eb4eSEric Schrock B_TRUE }, 357754d692b7SGeorge Wilson { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 357854d692b7SGeorge Wilson B_FALSE }, 357954d692b7SGeorge Wilson { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 358054d692b7SGeorge Wilson B_FALSE }, 358154d692b7SGeorge Wilson { zfs_ioc_dataset_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 358254d692b7SGeorge Wilson B_FALSE }, 358354d692b7SGeorge Wilson { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 358454d692b7SGeorge Wilson B_FALSE }, 358554d692b7SGeorge Wilson { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, B_TRUE }, 358654d692b7SGeorge Wilson { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, B_TRUE }, 358754d692b7SGeorge Wilson { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 358854d692b7SGeorge Wilson B_TRUE}, 358954d692b7SGeorge Wilson { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE, 359054d692b7SGeorge Wilson B_TRUE }, 359154d692b7SGeorge Wilson { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE, B_TRUE }, 359254d692b7SGeorge Wilson { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE, B_TRUE }, 359354d692b7SGeorge Wilson { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE, B_FALSE }, 359454d692b7SGeorge Wilson { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 359554d692b7SGeorge Wilson B_FALSE }, 359654d692b7SGeorge Wilson { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 359754d692b7SGeorge Wilson B_FALSE }, 359854d692b7SGeorge Wilson { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE, 359954d692b7SGeorge Wilson B_FALSE }, 360054d692b7SGeorge Wilson { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE, 360154d692b7SGeorge Wilson B_FALSE }, 360254d692b7SGeorge Wilson { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE, B_FALSE }, 360354d692b7SGeorge Wilson { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE, 360454d692b7SGeorge Wilson B_TRUE }, 360554d692b7SGeorge Wilson { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 360654d692b7SGeorge Wilson B_TRUE }, 360754d692b7SGeorge Wilson { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE, 360854d692b7SGeorge Wilson B_TRUE }, 360954d692b7SGeorge Wilson { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE, 361054d692b7SGeorge Wilson B_FALSE }, 36116e8a0f56SGeorge Wilson { zfs_ioc_obj_to_path, zfs_secpolicy_config, DATASET_NAME, B_FALSE, 36126e8a0f56SGeorge Wilson B_TRUE }, 361354d692b7SGeorge Wilson { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE, 361454d692b7SGeorge Wilson B_TRUE }, 361554d692b7SGeorge Wilson { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE, 361654d692b7SGeorge Wilson B_FALSE }, 361754d692b7SGeorge Wilson { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE, 361854d692b7SGeorge Wilson B_TRUE }, 361954d692b7SGeorge Wilson { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 362054d692b7SGeorge Wilson B_FALSE }, 362154d692b7SGeorge Wilson { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, DATASET_NAME, B_FALSE, 362254d692b7SGeorge Wilson B_FALSE }, 362354d692b7SGeorge Wilson { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE, B_FALSE }, 362454d692b7SGeorge Wilson { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE, 362554d692b7SGeorge Wilson B_TRUE }, 362654d692b7SGeorge Wilson { zfs_ioc_smb_acl, zfs_secpolicy_smb_acl, DATASET_NAME, B_FALSE, 362714843421SMatthew Ahrens B_FALSE }, 362814843421SMatthew Ahrens { zfs_ioc_userspace_one, zfs_secpolicy_userspace_one, 362914843421SMatthew Ahrens DATASET_NAME, B_FALSE, B_FALSE }, 363014843421SMatthew Ahrens { zfs_ioc_userspace_many, zfs_secpolicy_userspace_many, 363114843421SMatthew Ahrens DATASET_NAME, B_FALSE, B_FALSE }, 363214843421SMatthew Ahrens { zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 363314843421SMatthew Ahrens DATASET_NAME, B_FALSE, B_TRUE }, 3634842727c2SChris Kirby { zfs_ioc_hold, zfs_secpolicy_hold, DATASET_NAME, B_TRUE, B_TRUE }, 3635842727c2SChris Kirby { zfs_ioc_release, zfs_secpolicy_release, DATASET_NAME, B_TRUE, 3636842727c2SChris Kirby B_TRUE }, 3637842727c2SChris Kirby { zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 3638842727c2SChris Kirby B_TRUE } 3639fa9e4066Sahrens }; 3640fa9e4066Sahrens 364154d692b7SGeorge Wilson int 364254d692b7SGeorge Wilson pool_status_check(const char *name, zfs_ioc_namecheck_t type) 364354d692b7SGeorge Wilson { 364454d692b7SGeorge Wilson spa_t *spa; 364554d692b7SGeorge Wilson int error; 364654d692b7SGeorge Wilson 364754d692b7SGeorge Wilson ASSERT(type == POOL_NAME || type == DATASET_NAME); 364854d692b7SGeorge Wilson 364914843421SMatthew Ahrens error = spa_open(name, &spa, FTAG); 365054d692b7SGeorge Wilson if (error == 0) { 365154d692b7SGeorge Wilson if (spa_suspended(spa)) 365254d692b7SGeorge Wilson error = EAGAIN; 365354d692b7SGeorge Wilson spa_close(spa, FTAG); 365454d692b7SGeorge Wilson } 365554d692b7SGeorge Wilson return (error); 365654d692b7SGeorge Wilson } 365754d692b7SGeorge Wilson 3658fa9e4066Sahrens static int 3659fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 3660fa9e4066Sahrens { 3661fa9e4066Sahrens zfs_cmd_t *zc; 3662fa9e4066Sahrens uint_t vec; 36631d452cf5Sahrens int error, rc; 3664fa9e4066Sahrens 3665fa9e4066Sahrens if (getminor(dev) != 0) 3666fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 3667fa9e4066Sahrens 3668fa9e4066Sahrens vec = cmd - ZFS_IOC; 366991ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 3670fa9e4066Sahrens 3671fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 3672fa9e4066Sahrens return (EINVAL); 3673fa9e4066Sahrens 3674fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 3675fa9e4066Sahrens 3676478ed9adSEric Taylor error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag); 3677fa9e4066Sahrens 3678681d9761SEric Taylor if ((error == 0) && !(flag & FKIOCTL)) 3679ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 3680fa9e4066Sahrens 3681fa9e4066Sahrens /* 3682fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 3683fa9e4066Sahrens * the lower layers. 3684fa9e4066Sahrens */ 3685fa9e4066Sahrens if (error == 0) { 3686fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 3687478ed9adSEric Taylor zc->zc_iflags = flag & FKIOCTL; 3688fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 3689e7437265Sahrens case POOL_NAME: 3690fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 3691fa9e4066Sahrens error = EINVAL; 369254d692b7SGeorge Wilson if (zfs_ioc_vec[vec].zvec_pool_check) 369354d692b7SGeorge Wilson error = pool_status_check(zc->zc_name, 369454d692b7SGeorge Wilson zfs_ioc_vec[vec].zvec_namecheck); 3695fa9e4066Sahrens break; 3696fa9e4066Sahrens 3697e7437265Sahrens case DATASET_NAME: 3698fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 3699fa9e4066Sahrens error = EINVAL; 370054d692b7SGeorge Wilson if (zfs_ioc_vec[vec].zvec_pool_check) 370154d692b7SGeorge Wilson error = pool_status_check(zc->zc_name, 370254d692b7SGeorge Wilson zfs_ioc_vec[vec].zvec_namecheck); 3703fa9e4066Sahrens break; 37045ad82045Snd 3705e7437265Sahrens case NO_NAME: 37065ad82045Snd break; 3707fa9e4066Sahrens } 3708fa9e4066Sahrens } 3709fa9e4066Sahrens 3710fa9e4066Sahrens if (error == 0) 3711fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 3712fa9e4066Sahrens 3713478ed9adSEric Taylor rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag); 3714ecd6cf80Smarks if (error == 0) { 37151d452cf5Sahrens error = rc; 371614843421SMatthew Ahrens if (zfs_ioc_vec[vec].zvec_his_log) 3717ecd6cf80Smarks zfs_log_history(zc); 3718ecd6cf80Smarks } 3719fa9e4066Sahrens 3720fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 3721fa9e4066Sahrens return (error); 3722fa9e4066Sahrens } 3723fa9e4066Sahrens 3724fa9e4066Sahrens static int 3725fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3726fa9e4066Sahrens { 3727fa9e4066Sahrens if (cmd != DDI_ATTACH) 3728fa9e4066Sahrens return (DDI_FAILURE); 3729fa9e4066Sahrens 3730fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 3731fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 3732fa9e4066Sahrens return (DDI_FAILURE); 3733fa9e4066Sahrens 3734fa9e4066Sahrens zfs_dip = dip; 3735fa9e4066Sahrens 3736fa9e4066Sahrens ddi_report_dev(dip); 3737fa9e4066Sahrens 3738fa9e4066Sahrens return (DDI_SUCCESS); 3739fa9e4066Sahrens } 3740fa9e4066Sahrens 3741fa9e4066Sahrens static int 3742fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3743fa9e4066Sahrens { 3744fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 3745fa9e4066Sahrens return (DDI_FAILURE); 3746fa9e4066Sahrens 3747fa9e4066Sahrens if (cmd != DDI_DETACH) 3748fa9e4066Sahrens return (DDI_FAILURE); 3749fa9e4066Sahrens 3750fa9e4066Sahrens zfs_dip = NULL; 3751fa9e4066Sahrens 3752fa9e4066Sahrens ddi_prop_remove_all(dip); 3753fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 3754fa9e4066Sahrens 3755fa9e4066Sahrens return (DDI_SUCCESS); 3756fa9e4066Sahrens } 3757fa9e4066Sahrens 3758fa9e4066Sahrens /*ARGSUSED*/ 3759fa9e4066Sahrens static int 3760fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3761fa9e4066Sahrens { 3762fa9e4066Sahrens switch (infocmd) { 3763fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 3764fa9e4066Sahrens *result = zfs_dip; 3765fa9e4066Sahrens return (DDI_SUCCESS); 3766fa9e4066Sahrens 3767fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 3768a0965f35Sbonwick *result = (void *)0; 3769fa9e4066Sahrens return (DDI_SUCCESS); 3770fa9e4066Sahrens } 3771fa9e4066Sahrens 3772fa9e4066Sahrens return (DDI_FAILURE); 3773fa9e4066Sahrens } 3774fa9e4066Sahrens 3775fa9e4066Sahrens /* 3776fa9e4066Sahrens * OK, so this is a little weird. 3777fa9e4066Sahrens * 3778fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 3779fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3780fa9e4066Sahrens * 3781fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 3782fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 3783fa9e4066Sahrens */ 3784fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 3785fa9e4066Sahrens zvol_open, /* open */ 3786fa9e4066Sahrens zvol_close, /* close */ 3787fa9e4066Sahrens zvol_strategy, /* strategy */ 3788fa9e4066Sahrens nodev, /* print */ 3789e7cbe64fSgw zvol_dump, /* dump */ 3790fa9e4066Sahrens zvol_read, /* read */ 3791fa9e4066Sahrens zvol_write, /* write */ 3792fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 3793fa9e4066Sahrens nodev, /* devmap */ 3794fa9e4066Sahrens nodev, /* mmap */ 3795fa9e4066Sahrens nodev, /* segmap */ 3796fa9e4066Sahrens nochpoll, /* poll */ 3797fa9e4066Sahrens ddi_prop_op, /* prop_op */ 3798fa9e4066Sahrens NULL, /* streamtab */ 3799fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 3800fa9e4066Sahrens CB_REV, /* version */ 3801feb08c6bSbillm nodev, /* async read */ 3802feb08c6bSbillm nodev, /* async write */ 3803fa9e4066Sahrens }; 3804fa9e4066Sahrens 3805fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 3806fa9e4066Sahrens DEVO_REV, /* version */ 3807fa9e4066Sahrens 0, /* refcnt */ 3808fa9e4066Sahrens zfs_info, /* info */ 3809fa9e4066Sahrens nulldev, /* identify */ 3810fa9e4066Sahrens nulldev, /* probe */ 3811fa9e4066Sahrens zfs_attach, /* attach */ 3812fa9e4066Sahrens zfs_detach, /* detach */ 3813fa9e4066Sahrens nodev, /* reset */ 3814fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 381519397407SSherry Moore NULL, /* no bus operations */ 381619397407SSherry Moore NULL, /* power */ 381719397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 3818fa9e4066Sahrens }; 3819fa9e4066Sahrens 3820fa9e4066Sahrens static struct modldrv zfs_modldrv = { 382119397407SSherry Moore &mod_driverops, 382219397407SSherry Moore "ZFS storage pool", 382319397407SSherry Moore &zfs_dev_ops 3824fa9e4066Sahrens }; 3825fa9e4066Sahrens 3826fa9e4066Sahrens static struct modlinkage modlinkage = { 3827fa9e4066Sahrens MODREV_1, 3828fa9e4066Sahrens (void *)&zfs_modlfs, 3829fa9e4066Sahrens (void *)&zfs_modldrv, 3830fa9e4066Sahrens NULL 3831fa9e4066Sahrens }; 3832fa9e4066Sahrens 3833ec533521Sfr 3834ec533521Sfr uint_t zfs_fsyncer_key; 3835f18faf3fSek extern uint_t rrw_tsd_key; 3836ec533521Sfr 3837fa9e4066Sahrens int 3838fa9e4066Sahrens _init(void) 3839fa9e4066Sahrens { 3840fa9e4066Sahrens int error; 3841fa9e4066Sahrens 3842a0965f35Sbonwick spa_init(FREAD | FWRITE); 3843a0965f35Sbonwick zfs_init(); 3844a0965f35Sbonwick zvol_init(); 3845a0965f35Sbonwick 3846a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 3847a0965f35Sbonwick zvol_fini(); 3848a0965f35Sbonwick zfs_fini(); 3849a0965f35Sbonwick spa_fini(); 3850fa9e4066Sahrens return (error); 3851a0965f35Sbonwick } 3852fa9e4066Sahrens 3853ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 3854f18faf3fSek tsd_create(&rrw_tsd_key, NULL); 3855ec533521Sfr 3856fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 3857fa9e4066Sahrens ASSERT(error == 0); 3858ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3859fa9e4066Sahrens 3860fa9e4066Sahrens return (0); 3861fa9e4066Sahrens } 3862fa9e4066Sahrens 3863fa9e4066Sahrens int 3864fa9e4066Sahrens _fini(void) 3865fa9e4066Sahrens { 3866fa9e4066Sahrens int error; 3867fa9e4066Sahrens 3868ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3869fa9e4066Sahrens return (EBUSY); 3870fa9e4066Sahrens 3871fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3872fa9e4066Sahrens return (error); 3873fa9e4066Sahrens 3874fa9e4066Sahrens zvol_fini(); 3875fa9e4066Sahrens zfs_fini(); 3876fa9e4066Sahrens spa_fini(); 3877da6c28aaSamw if (zfs_nfsshare_inited) 3878ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 3879da6c28aaSamw if (zfs_smbshare_inited) 3880da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 3881da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 3882ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 3883fa9e4066Sahrens 3884ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 3885fa9e4066Sahrens ldi_ident_release(zfs_li); 3886fa9e4066Sahrens zfs_li = NULL; 3887ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 3888fa9e4066Sahrens 3889fa9e4066Sahrens return (error); 3890fa9e4066Sahrens } 3891fa9e4066Sahrens 3892fa9e4066Sahrens int 3893fa9e4066Sahrens _info(struct modinfo *modinfop) 3894fa9e4066Sahrens { 3895fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 3896fa9e4066Sahrens } 3897