1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 228525SEric.Schrock@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <sys/types.h> 27789Sahrens #include <sys/param.h> 28789Sahrens #include <sys/errno.h> 29789Sahrens #include <sys/uio.h> 30789Sahrens #include <sys/buf.h> 31789Sahrens #include <sys/modctl.h> 32789Sahrens #include <sys/open.h> 33789Sahrens #include <sys/file.h> 34789Sahrens #include <sys/kmem.h> 35789Sahrens #include <sys/conf.h> 36789Sahrens #include <sys/cmn_err.h> 37789Sahrens #include <sys/stat.h> 38789Sahrens #include <sys/zfs_ioctl.h> 395331Samw #include <sys/zfs_znode.h> 40789Sahrens #include <sys/zap.h> 41789Sahrens #include <sys/spa.h> 423912Slling #include <sys/spa_impl.h> 43789Sahrens #include <sys/vdev.h> 443912Slling #include <sys/vdev_impl.h> 45789Sahrens #include <sys/dmu.h> 46789Sahrens #include <sys/dsl_dir.h> 47789Sahrens #include <sys/dsl_dataset.h> 48789Sahrens #include <sys/dsl_prop.h> 494543Smarks #include <sys/dsl_deleg.h> 504543Smarks #include <sys/dmu_objset.h> 51789Sahrens #include <sys/ddi.h> 52789Sahrens #include <sys/sunddi.h> 53789Sahrens #include <sys/sunldi.h> 54789Sahrens #include <sys/policy.h> 55789Sahrens #include <sys/zone.h> 56789Sahrens #include <sys/nvpair.h> 57789Sahrens #include <sys/pathname.h> 58789Sahrens #include <sys/mount.h> 59789Sahrens #include <sys/sdt.h> 60789Sahrens #include <sys/fs/zfs.h> 61789Sahrens #include <sys/zfs_ctldir.h> 625331Samw #include <sys/zfs_dir.h> 632885Sahrens #include <sys/zvol.h> 644543Smarks #include <sharefs/share.h> 655326Sek110237 #include <sys/dmu_objset.h> 66789Sahrens 67789Sahrens #include "zfs_namecheck.h" 682676Seschrock #include "zfs_prop.h" 694543Smarks #include "zfs_deleg.h" 70789Sahrens 71789Sahrens extern struct modlfs zfs_modlfs; 72789Sahrens 73789Sahrens extern void zfs_init(void); 74789Sahrens extern void zfs_fini(void); 75789Sahrens 76789Sahrens ldi_ident_t zfs_li = NULL; 77789Sahrens dev_info_t *zfs_dip; 78789Sahrens 79789Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 804543Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 81789Sahrens 829234SGeorge.Wilson@Sun.COM typedef enum { 839234SGeorge.Wilson@Sun.COM NO_NAME, 849234SGeorge.Wilson@Sun.COM POOL_NAME, 859234SGeorge.Wilson@Sun.COM DATASET_NAME 869234SGeorge.Wilson@Sun.COM } zfs_ioc_namecheck_t; 879234SGeorge.Wilson@Sun.COM 88789Sahrens typedef struct zfs_ioc_vec { 89789Sahrens zfs_ioc_func_t *zvec_func; 90789Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 919234SGeorge.Wilson@Sun.COM zfs_ioc_namecheck_t zvec_namecheck; 924543Smarks boolean_t zvec_his_log; 939234SGeorge.Wilson@Sun.COM boolean_t zvec_pool_check; 94789Sahrens } zfs_ioc_vec_t; 95789Sahrens 969396SMatthew.Ahrens@Sun.COM /* This array is indexed by zfs_userquota_prop_t */ 979396SMatthew.Ahrens@Sun.COM static const char *userquota_perms[] = { 989396SMatthew.Ahrens@Sun.COM ZFS_DELEG_PERM_USERUSED, 999396SMatthew.Ahrens@Sun.COM ZFS_DELEG_PERM_USERQUOTA, 1009396SMatthew.Ahrens@Sun.COM ZFS_DELEG_PERM_GROUPUSED, 1019396SMatthew.Ahrens@Sun.COM ZFS_DELEG_PERM_GROUPQUOTA, 1029396SMatthew.Ahrens@Sun.COM }; 1039396SMatthew.Ahrens@Sun.COM 1049396SMatthew.Ahrens@Sun.COM static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 1058536SDavid.Pacheco@Sun.COM static void clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops); 1067184Stimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 1077184Stimh boolean_t *); 1087184Stimh int zfs_set_prop_nvlist(const char *, nvlist_t *); 1097184Stimh 110789Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 111789Sahrens void 112789Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 113789Sahrens { 114789Sahrens const char *newfile; 115789Sahrens char buf[256]; 116789Sahrens va_list adx; 117789Sahrens 118789Sahrens /* 119789Sahrens * Get rid of annoying "../common/" prefix to filename. 120789Sahrens */ 121789Sahrens newfile = strrchr(file, '/'); 122789Sahrens if (newfile != NULL) { 123789Sahrens newfile = newfile + 1; /* Get rid of leading / */ 124789Sahrens } else { 125789Sahrens newfile = file; 126789Sahrens } 127789Sahrens 128789Sahrens va_start(adx, fmt); 129789Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 130789Sahrens va_end(adx); 131789Sahrens 132789Sahrens /* 133789Sahrens * To get this data, use the zfs-dprintf probe as so: 134789Sahrens * dtrace -q -n 'zfs-dprintf \ 135789Sahrens * /stringof(arg0) == "dbuf.c"/ \ 136789Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 137789Sahrens * arg0 = file name 138789Sahrens * arg1 = function name 139789Sahrens * arg2 = line number 140789Sahrens * arg3 = message 141789Sahrens */ 142789Sahrens DTRACE_PROBE4(zfs__dprintf, 143789Sahrens char *, newfile, char *, func, int, line, char *, buf); 144789Sahrens } 145789Sahrens 1464543Smarks static void 1474715Sek110237 history_str_free(char *buf) 1484715Sek110237 { 1494715Sek110237 kmem_free(buf, HIS_MAX_RECORD_LEN); 1504715Sek110237 } 1514715Sek110237 1524715Sek110237 static char * 1534715Sek110237 history_str_get(zfs_cmd_t *zc) 1544715Sek110237 { 1554715Sek110237 char *buf; 1564715Sek110237 1574715Sek110237 if (zc->zc_history == NULL) 1584715Sek110237 return (NULL); 1594715Sek110237 1604715Sek110237 buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 1614715Sek110237 if (copyinstr((void *)(uintptr_t)zc->zc_history, 1624715Sek110237 buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 1634715Sek110237 history_str_free(buf); 1644715Sek110237 return (NULL); 1654715Sek110237 } 1664715Sek110237 1674715Sek110237 buf[HIS_MAX_RECORD_LEN -1] = '\0'; 1684715Sek110237 1694715Sek110237 return (buf); 1704715Sek110237 } 1714715Sek110237 1725375Stimh /* 1737042Sgw25295 * Check to see if the named dataset is currently defined as bootable 1747042Sgw25295 */ 1757042Sgw25295 static boolean_t 1767042Sgw25295 zfs_is_bootfs(const char *name) 1777042Sgw25295 { 178*10298SMatthew.Ahrens@Sun.COM objset_t *os; 179*10298SMatthew.Ahrens@Sun.COM 180*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_hold(name, FTAG, &os) == 0) { 181*10298SMatthew.Ahrens@Sun.COM boolean_t ret; 182*10298SMatthew.Ahrens@Sun.COM ret = (dmu_objset_id(os) == dmu_objset_spa(os)->spa_bootfs); 183*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 184*10298SMatthew.Ahrens@Sun.COM return (ret); 1857042Sgw25295 } 186*10298SMatthew.Ahrens@Sun.COM return (B_FALSE); 1877042Sgw25295 } 1887042Sgw25295 1897042Sgw25295 /* 1907184Stimh * zfs_earlier_version 1915375Stimh * 1925375Stimh * Return non-zero if the spa version is less than requested version. 1935375Stimh */ 1945331Samw static int 1957184Stimh zfs_earlier_version(const char *name, int version) 1965331Samw { 1975331Samw spa_t *spa; 1985331Samw 1995331Samw if (spa_open(name, &spa, FTAG) == 0) { 2005331Samw if (spa_version(spa) < version) { 2015331Samw spa_close(spa, FTAG); 2025331Samw return (1); 2035331Samw } 2045331Samw spa_close(spa, FTAG); 2055331Samw } 2065331Samw return (0); 2075331Samw } 2085331Samw 2095977Smarks /* 2106689Smaybee * zpl_earlier_version 2115977Smarks * 2126689Smaybee * Return TRUE if the ZPL version is less than requested version. 2135977Smarks */ 2146689Smaybee static boolean_t 2156689Smaybee zpl_earlier_version(const char *name, int version) 2165977Smarks { 2175977Smarks objset_t *os; 2186689Smaybee boolean_t rc = B_TRUE; 2195977Smarks 220*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_hold(name, FTAG, &os) == 0) { 2216689Smaybee uint64_t zplversion; 2226689Smaybee 223*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_type(os) != DMU_OST_ZFS) { 224*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 225*10298SMatthew.Ahrens@Sun.COM return (B_TRUE); 226*10298SMatthew.Ahrens@Sun.COM } 227*10298SMatthew.Ahrens@Sun.COM /* XXX reading from non-owned objset */ 2286689Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 2296689Smaybee rc = zplversion < version; 230*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 2315977Smarks } 2325977Smarks return (rc); 2335977Smarks } 2345977Smarks 2354715Sek110237 static void 2364543Smarks zfs_log_history(zfs_cmd_t *zc) 2374543Smarks { 2384543Smarks spa_t *spa; 2394603Sahrens char *buf; 2404543Smarks 2414715Sek110237 if ((buf = history_str_get(zc)) == NULL) 2424577Sahrens return; 2434577Sahrens 2444715Sek110237 if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 2454715Sek110237 if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 2464715Sek110237 (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 2474715Sek110237 spa_close(spa, FTAG); 2484543Smarks } 2494715Sek110237 history_str_free(buf); 2504543Smarks } 2514543Smarks 252789Sahrens /* 253789Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 254789Sahrens * and can be used in the local zone, as there is no associated dataset. 255789Sahrens */ 256789Sahrens /* ARGSUSED */ 257789Sahrens static int 2584543Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 259789Sahrens { 260789Sahrens return (0); 261789Sahrens } 262789Sahrens 263789Sahrens /* 264789Sahrens * Policy for dataset read operations (list children, get statistics). Requires 265789Sahrens * no privileges, but must be visible in the local zone. 266789Sahrens */ 267789Sahrens /* ARGSUSED */ 268789Sahrens static int 2694543Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 270789Sahrens { 271789Sahrens if (INGLOBALZONE(curproc) || 2724543Smarks zone_dataset_visible(zc->zc_name, NULL)) 273789Sahrens return (0); 274789Sahrens 275789Sahrens return (ENOENT); 276789Sahrens } 277789Sahrens 278789Sahrens static int 279789Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 280789Sahrens { 281789Sahrens uint64_t zoned; 282789Sahrens int writable = 1; 283789Sahrens 284789Sahrens /* 285789Sahrens * The dataset must be visible by this zone -- check this first 286789Sahrens * so they don't see EPERM on something they shouldn't know about. 287789Sahrens */ 288789Sahrens if (!INGLOBALZONE(curproc) && 289789Sahrens !zone_dataset_visible(dataset, &writable)) 290789Sahrens return (ENOENT); 291789Sahrens 292789Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 293789Sahrens return (ENOENT); 294789Sahrens 295789Sahrens if (INGLOBALZONE(curproc)) { 296789Sahrens /* 297789Sahrens * If the fs is zoned, only root can access it from the 298789Sahrens * global zone. 299789Sahrens */ 300789Sahrens if (secpolicy_zfs(cr) && zoned) 301789Sahrens return (EPERM); 302789Sahrens } else { 303789Sahrens /* 304789Sahrens * If we are in a local zone, the 'zoned' property must be set. 305789Sahrens */ 306789Sahrens if (!zoned) 307789Sahrens return (EPERM); 308789Sahrens 309789Sahrens /* must be writable by this zone */ 310789Sahrens if (!writable) 311789Sahrens return (EPERM); 312789Sahrens } 313789Sahrens return (0); 314789Sahrens } 315789Sahrens 316789Sahrens int 3174543Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 318789Sahrens { 319789Sahrens int error; 320789Sahrens 3214543Smarks error = zfs_dozonecheck(name, cr); 3224543Smarks if (error == 0) { 3234543Smarks error = secpolicy_zfs(cr); 3244670Sahrens if (error) 3254543Smarks error = dsl_deleg_access(name, perm, cr); 3264543Smarks } 3274543Smarks return (error); 3284543Smarks } 3294543Smarks 3304543Smarks static int 3314543Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 3324543Smarks { 3334543Smarks /* 3344543Smarks * Check permissions for special properties. 3354543Smarks */ 3364543Smarks switch (prop) { 3374543Smarks case ZFS_PROP_ZONED: 3384543Smarks /* 3394543Smarks * Disallow setting of 'zoned' from within a local zone. 3404543Smarks */ 3414543Smarks if (!INGLOBALZONE(curproc)) 3424543Smarks return (EPERM); 3434543Smarks break; 344789Sahrens 3454543Smarks case ZFS_PROP_QUOTA: 3464543Smarks if (!INGLOBALZONE(curproc)) { 3474543Smarks uint64_t zoned; 3484543Smarks char setpoint[MAXNAMELEN]; 3494543Smarks /* 3504543Smarks * Unprivileged users are allowed to modify the 3514543Smarks * quota on things *under* (ie. contained by) 3524543Smarks * the thing they own. 3534543Smarks */ 3544543Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 3554543Smarks setpoint)) 3564543Smarks return (EPERM); 3574670Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 3584543Smarks return (EPERM); 3594543Smarks } 3604670Sahrens break; 3614543Smarks } 3624543Smarks 3634787Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 364789Sahrens } 365789Sahrens 3664543Smarks int 3674543Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 3684543Smarks { 3694543Smarks int error; 3704543Smarks 3714543Smarks error = zfs_dozonecheck(zc->zc_name, cr); 3724543Smarks if (error) 3734543Smarks return (error); 3744543Smarks 3754543Smarks /* 3764543Smarks * permission to set permissions will be evaluated later in 3774543Smarks * dsl_deleg_can_allow() 3784543Smarks */ 3794543Smarks return (0); 3804543Smarks } 3814543Smarks 3824543Smarks int 3834543Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 3844543Smarks { 3854543Smarks int error; 3864543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 3874543Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 3884543Smarks if (error == 0) 3894543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 3904543Smarks ZFS_DELEG_PERM_MOUNT, cr); 3914543Smarks return (error); 3924543Smarks } 3934543Smarks 3944543Smarks int 3954543Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 3964543Smarks { 3974543Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 3984543Smarks ZFS_DELEG_PERM_SEND, cr)); 3994543Smarks } 4004543Smarks 4018845Samw@Sun.COM static int 4028845Samw@Sun.COM zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) 4038845Samw@Sun.COM { 4048845Samw@Sun.COM vnode_t *vp; 4058845Samw@Sun.COM int error; 4068845Samw@Sun.COM 4078845Samw@Sun.COM if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 4088845Samw@Sun.COM NO_FOLLOW, NULL, &vp)) != 0) 4098845Samw@Sun.COM return (error); 4108845Samw@Sun.COM 4118845Samw@Sun.COM /* Now make sure mntpnt and dataset are ZFS */ 4128845Samw@Sun.COM 4138845Samw@Sun.COM if (vp->v_vfsp->vfs_fstype != zfsfstype || 4148845Samw@Sun.COM (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 4158845Samw@Sun.COM zc->zc_name) != 0)) { 4168845Samw@Sun.COM VN_RELE(vp); 4178845Samw@Sun.COM return (EPERM); 4188845Samw@Sun.COM } 4198845Samw@Sun.COM 4208845Samw@Sun.COM VN_RELE(vp); 4218845Samw@Sun.COM return (dsl_deleg_access(zc->zc_name, 4228845Samw@Sun.COM ZFS_DELEG_PERM_SHARE, cr)); 4238845Samw@Sun.COM } 4248845Samw@Sun.COM 4254543Smarks int 4264543Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 4274543Smarks { 4284543Smarks if (!INGLOBALZONE(curproc)) 4294543Smarks return (EPERM); 4304543Smarks 4315367Sahrens if (secpolicy_nfs(cr) == 0) { 4324543Smarks return (0); 4334543Smarks } else { 4348845Samw@Sun.COM return (zfs_secpolicy_deleg_share(zc, cr)); 4358845Samw@Sun.COM } 4368845Samw@Sun.COM } 4378845Samw@Sun.COM 4388845Samw@Sun.COM int 4398845Samw@Sun.COM zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) 4408845Samw@Sun.COM { 4418845Samw@Sun.COM if (!INGLOBALZONE(curproc)) 4428845Samw@Sun.COM return (EPERM); 4438845Samw@Sun.COM 4448845Samw@Sun.COM if (secpolicy_smb(cr) == 0) { 4458845Samw@Sun.COM return (0); 4468845Samw@Sun.COM } else { 4478845Samw@Sun.COM return (zfs_secpolicy_deleg_share(zc, cr)); 4484543Smarks } 4494543Smarks } 4504543Smarks 451789Sahrens static int 4524543Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 453789Sahrens { 454789Sahrens char *cp; 455789Sahrens 456789Sahrens /* 457789Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 458789Sahrens */ 4594543Smarks (void) strncpy(parent, datasetname, parentsize); 4604543Smarks cp = strrchr(parent, '@'); 461789Sahrens if (cp != NULL) { 462789Sahrens cp[0] = '\0'; 463789Sahrens } else { 4644543Smarks cp = strrchr(parent, '/'); 465789Sahrens if (cp == NULL) 466789Sahrens return (ENOENT); 467789Sahrens cp[0] = '\0'; 468789Sahrens } 469789Sahrens 4704543Smarks return (0); 4714543Smarks } 4724543Smarks 4734543Smarks int 4744543Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 4754543Smarks { 4764543Smarks int error; 4774543Smarks 4784543Smarks if ((error = zfs_secpolicy_write_perms(name, 4794543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 4804543Smarks return (error); 4814543Smarks 4824543Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 4834543Smarks } 4844543Smarks 4854543Smarks static int 4864543Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 4874543Smarks { 4884543Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 4894543Smarks } 4904543Smarks 4914543Smarks /* 4924543Smarks * Must have sys_config privilege to check the iscsi permission 4934543Smarks */ 4944543Smarks /* ARGSUSED */ 4954543Smarks static int 4964543Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 4974543Smarks { 4984543Smarks return (secpolicy_zfs(cr)); 4994543Smarks } 5004543Smarks 5014543Smarks int 5024543Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 5034543Smarks { 5044543Smarks char parentname[MAXNAMELEN]; 5054543Smarks int error; 5064543Smarks 5074543Smarks if ((error = zfs_secpolicy_write_perms(from, 5084543Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 5094543Smarks return (error); 5104543Smarks 5114543Smarks if ((error = zfs_secpolicy_write_perms(from, 5124543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 5134543Smarks return (error); 5144543Smarks 5154543Smarks if ((error = zfs_get_parent(to, parentname, 5164543Smarks sizeof (parentname))) != 0) 5174543Smarks return (error); 5184543Smarks 5194543Smarks if ((error = zfs_secpolicy_write_perms(parentname, 5204543Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 5214543Smarks return (error); 5224543Smarks 5234543Smarks if ((error = zfs_secpolicy_write_perms(parentname, 5244543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 5254543Smarks return (error); 5264543Smarks 5274543Smarks return (error); 5284543Smarks } 5294543Smarks 5304543Smarks static int 5314543Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 5324543Smarks { 5334543Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 5344543Smarks } 5354543Smarks 5364543Smarks static int 5374543Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 5384543Smarks { 5394543Smarks char parentname[MAXNAMELEN]; 5404543Smarks objset_t *clone; 5414543Smarks int error; 5424543Smarks 5434543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 5444543Smarks ZFS_DELEG_PERM_PROMOTE, cr); 5454543Smarks if (error) 5464543Smarks return (error); 5474543Smarks 548*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(zc->zc_name, FTAG, &clone); 5494543Smarks 5504543Smarks if (error == 0) { 5514543Smarks dsl_dataset_t *pclone = NULL; 5524543Smarks dsl_dir_t *dd; 553*10298SMatthew.Ahrens@Sun.COM dd = clone->os_dsl_dataset->ds_dir; 5544543Smarks 5554543Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 5566689Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 5576689Smaybee dd->dd_phys->dd_origin_obj, FTAG, &pclone); 5584543Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 5594543Smarks if (error) { 560*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(clone, FTAG); 5614543Smarks return (error); 5624543Smarks } 5634543Smarks 5644543Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 5654543Smarks ZFS_DELEG_PERM_MOUNT, cr); 5664543Smarks 5674543Smarks dsl_dataset_name(pclone, parentname); 568*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(clone, FTAG); 5696689Smaybee dsl_dataset_rele(pclone, FTAG); 5704543Smarks if (error == 0) 5714543Smarks error = zfs_secpolicy_write_perms(parentname, 5724543Smarks ZFS_DELEG_PERM_PROMOTE, cr); 5734543Smarks } 5744543Smarks return (error); 5754543Smarks } 5764543Smarks 5774543Smarks static int 5784543Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 5794543Smarks { 5804543Smarks int error; 5814543Smarks 5824543Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 5834543Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 5844543Smarks return (error); 5854543Smarks 5864543Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 5874543Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 5884543Smarks return (error); 5894543Smarks 5904543Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 5914543Smarks ZFS_DELEG_PERM_CREATE, cr)); 5924543Smarks } 5934543Smarks 5944543Smarks int 5954543Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 5964543Smarks { 5974543Smarks int error; 5984543Smarks 5994543Smarks if ((error = zfs_secpolicy_write_perms(name, 6004543Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 6014543Smarks return (error); 6024543Smarks 6034543Smarks error = zfs_secpolicy_write_perms(name, 6044543Smarks ZFS_DELEG_PERM_MOUNT, cr); 6054543Smarks 6064543Smarks return (error); 6074543Smarks } 6084543Smarks 6094543Smarks static int 6104543Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 6114543Smarks { 6124543Smarks 6134543Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 6144543Smarks } 6154543Smarks 6164543Smarks static int 6174543Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 6184543Smarks { 6194543Smarks char parentname[MAXNAMELEN]; 6204543Smarks int error; 6214543Smarks 6224543Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 6234543Smarks sizeof (parentname))) != 0) 6244543Smarks return (error); 6254543Smarks 6264543Smarks if (zc->zc_value[0] != '\0') { 6274543Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 6284543Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 6294543Smarks return (error); 6304543Smarks } 6314543Smarks 6324543Smarks if ((error = zfs_secpolicy_write_perms(parentname, 6334543Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 6344543Smarks return (error); 6354543Smarks 6364543Smarks error = zfs_secpolicy_write_perms(parentname, 6374543Smarks ZFS_DELEG_PERM_MOUNT, cr); 6384543Smarks 6394543Smarks return (error); 6404543Smarks } 6414543Smarks 6424543Smarks static int 6434543Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 6444543Smarks { 6454543Smarks int error; 6464543Smarks 6474543Smarks error = secpolicy_fs_unmount(cr, NULL); 6484543Smarks if (error) { 6494543Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 6504543Smarks } 6514543Smarks return (error); 652789Sahrens } 653789Sahrens 654789Sahrens /* 655789Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 656789Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 657789Sahrens */ 658789Sahrens /* ARGSUSED */ 659789Sahrens static int 6604543Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 661789Sahrens { 662789Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 663789Sahrens return (EPERM); 664789Sahrens 665789Sahrens return (0); 666789Sahrens } 667789Sahrens 668789Sahrens /* 6694543Smarks * Just like zfs_secpolicy_config, except that we will check for 6704543Smarks * mount permission on the dataset for permission to create/remove 6714543Smarks * the minor nodes. 6724543Smarks */ 6734543Smarks static int 6744543Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 6754543Smarks { 6764543Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 6774543Smarks return (dsl_deleg_access(zc->zc_name, 6784543Smarks ZFS_DELEG_PERM_MOUNT, cr)); 6794543Smarks } 6804543Smarks 6814543Smarks return (0); 6824543Smarks } 6834543Smarks 6844543Smarks /* 6851544Seschrock * Policy for fault injection. Requires all privileges. 6861544Seschrock */ 6871544Seschrock /* ARGSUSED */ 6881544Seschrock static int 6894543Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 6901544Seschrock { 6911544Seschrock return (secpolicy_zinject(cr)); 6921544Seschrock } 6931544Seschrock 6944849Sahrens static int 6954849Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 6964849Sahrens { 6974849Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 6984849Sahrens 6995094Slling if (prop == ZPROP_INVAL) { 7004849Sahrens if (!zfs_prop_user(zc->zc_value)) 7014849Sahrens return (EINVAL); 7024849Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 7034849Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 7044849Sahrens } else { 7054849Sahrens if (!zfs_prop_inheritable(prop)) 7064849Sahrens return (EINVAL); 7074849Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 7084849Sahrens } 7094849Sahrens } 7104849Sahrens 7119396SMatthew.Ahrens@Sun.COM static int 7129396SMatthew.Ahrens@Sun.COM zfs_secpolicy_userspace_one(zfs_cmd_t *zc, cred_t *cr) 7139396SMatthew.Ahrens@Sun.COM { 7149396SMatthew.Ahrens@Sun.COM int err = zfs_secpolicy_read(zc, cr); 7159396SMatthew.Ahrens@Sun.COM if (err) 7169396SMatthew.Ahrens@Sun.COM return (err); 7179396SMatthew.Ahrens@Sun.COM 7189396SMatthew.Ahrens@Sun.COM if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 7199396SMatthew.Ahrens@Sun.COM return (EINVAL); 7209396SMatthew.Ahrens@Sun.COM 7219396SMatthew.Ahrens@Sun.COM if (zc->zc_value[0] == 0) { 7229396SMatthew.Ahrens@Sun.COM /* 7239396SMatthew.Ahrens@Sun.COM * They are asking about a posix uid/gid. If it's 7249396SMatthew.Ahrens@Sun.COM * themself, allow it. 7259396SMatthew.Ahrens@Sun.COM */ 7269396SMatthew.Ahrens@Sun.COM if (zc->zc_objset_type == ZFS_PROP_USERUSED || 7279396SMatthew.Ahrens@Sun.COM zc->zc_objset_type == ZFS_PROP_USERQUOTA) { 7289396SMatthew.Ahrens@Sun.COM if (zc->zc_guid == crgetuid(cr)) 7299396SMatthew.Ahrens@Sun.COM return (0); 7309396SMatthew.Ahrens@Sun.COM } else { 7319396SMatthew.Ahrens@Sun.COM if (groupmember(zc->zc_guid, cr)) 7329396SMatthew.Ahrens@Sun.COM return (0); 7339396SMatthew.Ahrens@Sun.COM } 7349396SMatthew.Ahrens@Sun.COM } 7359396SMatthew.Ahrens@Sun.COM 7369396SMatthew.Ahrens@Sun.COM return (zfs_secpolicy_write_perms(zc->zc_name, 7379396SMatthew.Ahrens@Sun.COM userquota_perms[zc->zc_objset_type], cr)); 7389396SMatthew.Ahrens@Sun.COM } 7399396SMatthew.Ahrens@Sun.COM 7409396SMatthew.Ahrens@Sun.COM static int 7419396SMatthew.Ahrens@Sun.COM zfs_secpolicy_userspace_many(zfs_cmd_t *zc, cred_t *cr) 7429396SMatthew.Ahrens@Sun.COM { 7439396SMatthew.Ahrens@Sun.COM int err = zfs_secpolicy_read(zc, cr); 7449396SMatthew.Ahrens@Sun.COM if (err) 7459396SMatthew.Ahrens@Sun.COM return (err); 7469396SMatthew.Ahrens@Sun.COM 7479396SMatthew.Ahrens@Sun.COM if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 7489396SMatthew.Ahrens@Sun.COM return (EINVAL); 7499396SMatthew.Ahrens@Sun.COM 7509396SMatthew.Ahrens@Sun.COM return (zfs_secpolicy_write_perms(zc->zc_name, 7519396SMatthew.Ahrens@Sun.COM userquota_perms[zc->zc_objset_type], cr)); 7529396SMatthew.Ahrens@Sun.COM } 7539396SMatthew.Ahrens@Sun.COM 7549396SMatthew.Ahrens@Sun.COM static int 7559396SMatthew.Ahrens@Sun.COM zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, cred_t *cr) 7569396SMatthew.Ahrens@Sun.COM { 7579396SMatthew.Ahrens@Sun.COM return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, cr)); 7589396SMatthew.Ahrens@Sun.COM } 7599396SMatthew.Ahrens@Sun.COM 76010242Schris.kirby@sun.com static int 76110242Schris.kirby@sun.com zfs_secpolicy_hold(zfs_cmd_t *zc, cred_t *cr) 76210242Schris.kirby@sun.com { 76310242Schris.kirby@sun.com return (zfs_secpolicy_write_perms(zc->zc_name, 76410242Schris.kirby@sun.com ZFS_DELEG_PERM_HOLD, cr)); 76510242Schris.kirby@sun.com } 76610242Schris.kirby@sun.com 76710242Schris.kirby@sun.com static int 76810242Schris.kirby@sun.com zfs_secpolicy_release(zfs_cmd_t *zc, cred_t *cr) 76910242Schris.kirby@sun.com { 77010242Schris.kirby@sun.com return (zfs_secpolicy_write_perms(zc->zc_name, 77110242Schris.kirby@sun.com ZFS_DELEG_PERM_RELEASE, cr)); 77210242Schris.kirby@sun.com } 77310242Schris.kirby@sun.com 7741544Seschrock /* 775789Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 776789Sahrens */ 777789Sahrens static int 7789643SEric.Taylor@Sun.COM get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) 779789Sahrens { 780789Sahrens char *packed; 781789Sahrens int error; 7825094Slling nvlist_t *list = NULL; 783789Sahrens 784789Sahrens /* 7852676Seschrock * Read in and unpack the user-supplied nvlist. 786789Sahrens */ 7875094Slling if (size == 0) 788789Sahrens return (EINVAL); 789789Sahrens 790789Sahrens packed = kmem_alloc(size, KM_SLEEP); 791789Sahrens 7929643SEric.Taylor@Sun.COM if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 7939643SEric.Taylor@Sun.COM iflag)) != 0) { 794789Sahrens kmem_free(packed, size); 795789Sahrens return (error); 796789Sahrens } 797789Sahrens 7985094Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 799789Sahrens kmem_free(packed, size); 800789Sahrens return (error); 801789Sahrens } 802789Sahrens 803789Sahrens kmem_free(packed, size); 804789Sahrens 8055094Slling *nvp = list; 806789Sahrens return (0); 807789Sahrens } 808789Sahrens 809789Sahrens static int 8102676Seschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 8112676Seschrock { 8122676Seschrock char *packed = NULL; 8132676Seschrock size_t size; 8142676Seschrock int error; 8152676Seschrock 8162676Seschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 8172676Seschrock 8182676Seschrock if (size > zc->zc_nvlist_dst_size) { 8192676Seschrock error = ENOMEM; 8202676Seschrock } else { 8214611Smarks packed = kmem_alloc(size, KM_SLEEP); 8222676Seschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 8232676Seschrock KM_SLEEP) == 0); 8249643SEric.Taylor@Sun.COM error = ddi_copyout(packed, 8259643SEric.Taylor@Sun.COM (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags); 8262676Seschrock kmem_free(packed, size); 8272676Seschrock } 8282676Seschrock 8292676Seschrock zc->zc_nvlist_dst_size = size; 8302676Seschrock return (error); 8312676Seschrock } 8322676Seschrock 8332676Seschrock static int 8349396SMatthew.Ahrens@Sun.COM getzfsvfs(const char *dsname, zfsvfs_t **zvp) 8359396SMatthew.Ahrens@Sun.COM { 8369396SMatthew.Ahrens@Sun.COM objset_t *os; 8379396SMatthew.Ahrens@Sun.COM int error; 8389396SMatthew.Ahrens@Sun.COM 839*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(dsname, FTAG, &os); 8409396SMatthew.Ahrens@Sun.COM if (error) 8419396SMatthew.Ahrens@Sun.COM return (error); 842*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_type(os) != DMU_OST_ZFS) { 843*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 844*10298SMatthew.Ahrens@Sun.COM return (EINVAL); 845*10298SMatthew.Ahrens@Sun.COM } 846*10298SMatthew.Ahrens@Sun.COM 847*10298SMatthew.Ahrens@Sun.COM mutex_enter(&os->os_user_ptr_lock); 8489396SMatthew.Ahrens@Sun.COM *zvp = dmu_objset_get_user(os); 8499396SMatthew.Ahrens@Sun.COM if (*zvp) { 8509396SMatthew.Ahrens@Sun.COM VFS_HOLD((*zvp)->z_vfs); 8519396SMatthew.Ahrens@Sun.COM } else { 8529396SMatthew.Ahrens@Sun.COM error = ESRCH; 8539396SMatthew.Ahrens@Sun.COM } 854*10298SMatthew.Ahrens@Sun.COM mutex_exit(&os->os_user_ptr_lock); 855*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 8569396SMatthew.Ahrens@Sun.COM return (error); 8579396SMatthew.Ahrens@Sun.COM } 8589396SMatthew.Ahrens@Sun.COM 8599396SMatthew.Ahrens@Sun.COM /* 8609396SMatthew.Ahrens@Sun.COM * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 8619396SMatthew.Ahrens@Sun.COM * case its z_vfs will be NULL, and it will be opened as the owner. 8629396SMatthew.Ahrens@Sun.COM */ 8639396SMatthew.Ahrens@Sun.COM static int 864*10298SMatthew.Ahrens@Sun.COM zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zvp) 8659396SMatthew.Ahrens@Sun.COM { 8669396SMatthew.Ahrens@Sun.COM int error = 0; 8679396SMatthew.Ahrens@Sun.COM 8689396SMatthew.Ahrens@Sun.COM if (getzfsvfs(name, zvp) != 0) 869*10298SMatthew.Ahrens@Sun.COM error = zfsvfs_create(name, zvp); 8709396SMatthew.Ahrens@Sun.COM if (error == 0) { 8719396SMatthew.Ahrens@Sun.COM rrw_enter(&(*zvp)->z_teardown_lock, RW_READER, tag); 8729396SMatthew.Ahrens@Sun.COM if ((*zvp)->z_unmounted) { 8739396SMatthew.Ahrens@Sun.COM /* 8749396SMatthew.Ahrens@Sun.COM * XXX we could probably try again, since the unmounting 8759396SMatthew.Ahrens@Sun.COM * thread should be just about to disassociate the 8769396SMatthew.Ahrens@Sun.COM * objset from the zfsvfs. 8779396SMatthew.Ahrens@Sun.COM */ 8789396SMatthew.Ahrens@Sun.COM rrw_exit(&(*zvp)->z_teardown_lock, tag); 8799396SMatthew.Ahrens@Sun.COM return (EBUSY); 8809396SMatthew.Ahrens@Sun.COM } 8819396SMatthew.Ahrens@Sun.COM } 8829396SMatthew.Ahrens@Sun.COM return (error); 8839396SMatthew.Ahrens@Sun.COM } 8849396SMatthew.Ahrens@Sun.COM 8859396SMatthew.Ahrens@Sun.COM static void 8869396SMatthew.Ahrens@Sun.COM zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 8879396SMatthew.Ahrens@Sun.COM { 8889396SMatthew.Ahrens@Sun.COM rrw_exit(&zfsvfs->z_teardown_lock, tag); 8899396SMatthew.Ahrens@Sun.COM 8909396SMatthew.Ahrens@Sun.COM if (zfsvfs->z_vfs) { 8919396SMatthew.Ahrens@Sun.COM VFS_RELE(zfsvfs->z_vfs); 8929396SMatthew.Ahrens@Sun.COM } else { 893*10298SMatthew.Ahrens@Sun.COM dmu_objset_disown(zfsvfs->z_os, zfsvfs); 8949396SMatthew.Ahrens@Sun.COM zfsvfs_free(zfsvfs); 8959396SMatthew.Ahrens@Sun.COM } 8969396SMatthew.Ahrens@Sun.COM } 8979396SMatthew.Ahrens@Sun.COM 8989396SMatthew.Ahrens@Sun.COM static int 899789Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 900789Sahrens { 901789Sahrens int error; 9025094Slling nvlist_t *config, *props = NULL; 9037184Stimh nvlist_t *rootprops = NULL; 9047184Stimh nvlist_t *zplprops = NULL; 9054715Sek110237 char *buf; 906789Sahrens 9075094Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 9089643SEric.Taylor@Sun.COM zc->zc_iflags, &config)) 9094988Sek110237 return (error); 9104715Sek110237 9115094Slling if (zc->zc_nvlist_src_size != 0 && (error = 9129643SEric.Taylor@Sun.COM get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 9139643SEric.Taylor@Sun.COM zc->zc_iflags, &props))) { 9145094Slling nvlist_free(config); 9155094Slling return (error); 9165094Slling } 9175094Slling 9187184Stimh if (props) { 9197184Stimh nvlist_t *nvl = NULL; 9207184Stimh uint64_t version = SPA_VERSION; 9217184Stimh 9227184Stimh (void) nvlist_lookup_uint64(props, 9237184Stimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 9247184Stimh if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 9257184Stimh error = EINVAL; 9267184Stimh goto pool_props_bad; 9277184Stimh } 9287184Stimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 9297184Stimh if (nvl) { 9307184Stimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 9317184Stimh if (error != 0) { 9327184Stimh nvlist_free(config); 9337184Stimh nvlist_free(props); 9347184Stimh return (error); 9357184Stimh } 9367184Stimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 9377184Stimh } 9387184Stimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 9397184Stimh error = zfs_fill_zplprops_root(version, rootprops, 9407184Stimh zplprops, NULL); 9417184Stimh if (error) 9427184Stimh goto pool_props_bad; 9437184Stimh } 9447184Stimh 9454988Sek110237 buf = history_str_get(zc); 946789Sahrens 9477184Stimh error = spa_create(zc->zc_name, config, props, buf, zplprops); 9487184Stimh 9497184Stimh /* 9507184Stimh * Set the remaining root properties 9517184Stimh */ 9527184Stimh if (!error && 9537184Stimh (error = zfs_set_prop_nvlist(zc->zc_name, rootprops)) != 0) 9547184Stimh (void) spa_destroy(zc->zc_name); 955789Sahrens 9564988Sek110237 if (buf != NULL) 9574988Sek110237 history_str_free(buf); 9585094Slling 9597184Stimh pool_props_bad: 9607184Stimh nvlist_free(rootprops); 9617184Stimh nvlist_free(zplprops); 962789Sahrens nvlist_free(config); 9637184Stimh nvlist_free(props); 9645094Slling 965789Sahrens return (error); 966789Sahrens } 967789Sahrens 968789Sahrens static int 969789Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 970789Sahrens { 9714543Smarks int error; 9724543Smarks zfs_log_history(zc); 9734543Smarks error = spa_destroy(zc->zc_name); 9744543Smarks return (error); 975789Sahrens } 976789Sahrens 977789Sahrens static int 978789Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 979789Sahrens { 980789Sahrens int error; 9815094Slling nvlist_t *config, *props = NULL; 982789Sahrens uint64_t guid; 983789Sahrens 9845094Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 9859643SEric.Taylor@Sun.COM zc->zc_iflags, &config)) != 0) 986789Sahrens return (error); 987789Sahrens 9885094Slling if (zc->zc_nvlist_src_size != 0 && (error = 9899643SEric.Taylor@Sun.COM get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 9909643SEric.Taylor@Sun.COM zc->zc_iflags, &props))) { 9915094Slling nvlist_free(config); 9925094Slling return (error); 9935094Slling } 9945094Slling 995789Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 9961544Seschrock guid != zc->zc_guid) 997789Sahrens error = EINVAL; 9986643Seschrock else if (zc->zc_cookie) 9999425SEric.Schrock@Sun.COM error = spa_import_verbatim(zc->zc_name, config, 10006643Seschrock props); 1001789Sahrens else 10025094Slling error = spa_import(zc->zc_name, config, props); 1003789Sahrens 1004789Sahrens nvlist_free(config); 1005789Sahrens 10065094Slling if (props) 10075094Slling nvlist_free(props); 10085094Slling 1009789Sahrens return (error); 1010789Sahrens } 1011789Sahrens 1012789Sahrens static int 1013789Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 1014789Sahrens { 10154543Smarks int error; 10167214Slling boolean_t force = (boolean_t)zc->zc_cookie; 10178211SGeorge.Wilson@Sun.COM boolean_t hardforce = (boolean_t)zc->zc_guid; 10187214Slling 10194543Smarks zfs_log_history(zc); 10208211SGeorge.Wilson@Sun.COM error = spa_export(zc->zc_name, NULL, force, hardforce); 10214543Smarks return (error); 1022789Sahrens } 1023789Sahrens 1024789Sahrens static int 1025789Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 1026789Sahrens { 1027789Sahrens nvlist_t *configs; 1028789Sahrens int error; 1029789Sahrens 1030789Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1031789Sahrens return (EEXIST); 1032789Sahrens 10332676Seschrock error = put_nvlist(zc, configs); 1034789Sahrens 1035789Sahrens nvlist_free(configs); 1036789Sahrens 1037789Sahrens return (error); 1038789Sahrens } 1039789Sahrens 1040789Sahrens static int 1041789Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 1042789Sahrens { 1043789Sahrens nvlist_t *config; 1044789Sahrens int error; 10451544Seschrock int ret = 0; 1046789Sahrens 10472676Seschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 10482676Seschrock sizeof (zc->zc_value)); 1049789Sahrens 1050789Sahrens if (config != NULL) { 10512676Seschrock ret = put_nvlist(zc, config); 1052789Sahrens nvlist_free(config); 10531544Seschrock 10541544Seschrock /* 10551544Seschrock * The config may be present even if 'error' is non-zero. 10561544Seschrock * In this case we return success, and preserve the real errno 10571544Seschrock * in 'zc_cookie'. 10581544Seschrock */ 10591544Seschrock zc->zc_cookie = error; 1060789Sahrens } else { 10611544Seschrock ret = error; 1062789Sahrens } 1063789Sahrens 10641544Seschrock return (ret); 1065789Sahrens } 1066789Sahrens 1067789Sahrens /* 1068789Sahrens * Try to import the given pool, returning pool stats as appropriate so that 1069789Sahrens * user land knows which devices are available and overall pool health. 1070789Sahrens */ 1071789Sahrens static int 1072789Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1073789Sahrens { 1074789Sahrens nvlist_t *tryconfig, *config; 1075789Sahrens int error; 1076789Sahrens 10775094Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 10789643SEric.Taylor@Sun.COM zc->zc_iflags, &tryconfig)) != 0) 1079789Sahrens return (error); 1080789Sahrens 1081789Sahrens config = spa_tryimport(tryconfig); 1082789Sahrens 1083789Sahrens nvlist_free(tryconfig); 1084789Sahrens 1085789Sahrens if (config == NULL) 1086789Sahrens return (EINVAL); 1087789Sahrens 10882676Seschrock error = put_nvlist(zc, config); 1089789Sahrens nvlist_free(config); 1090789Sahrens 1091789Sahrens return (error); 1092789Sahrens } 1093789Sahrens 1094789Sahrens static int 1095789Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 1096789Sahrens { 1097789Sahrens spa_t *spa; 1098789Sahrens int error; 1099789Sahrens 11002926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 11012926Sek110237 return (error); 11022926Sek110237 11037046Sahrens error = spa_scrub(spa, zc->zc_cookie); 11042926Sek110237 11052926Sek110237 spa_close(spa, FTAG); 11062926Sek110237 1107789Sahrens return (error); 1108789Sahrens } 1109789Sahrens 1110789Sahrens static int 1111789Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 1112789Sahrens { 1113789Sahrens spa_t *spa; 1114789Sahrens int error; 1115789Sahrens 1116789Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1117789Sahrens if (error == 0) { 1118789Sahrens spa_freeze(spa); 1119789Sahrens spa_close(spa, FTAG); 1120789Sahrens } 1121789Sahrens return (error); 1122789Sahrens } 1123789Sahrens 1124789Sahrens static int 11251760Seschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 11261760Seschrock { 11271760Seschrock spa_t *spa; 11281760Seschrock int error; 11291760Seschrock 11302926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 11312926Sek110237 return (error); 11322926Sek110237 11335118Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 11345118Slling spa_close(spa, FTAG); 11355118Slling return (EINVAL); 11365118Slling } 11375118Slling 11385094Slling spa_upgrade(spa, zc->zc_cookie); 11392926Sek110237 spa_close(spa, FTAG); 11402926Sek110237 11412926Sek110237 return (error); 11422926Sek110237 } 11432926Sek110237 11442926Sek110237 static int 11452926Sek110237 zfs_ioc_pool_get_history(zfs_cmd_t *zc) 11462926Sek110237 { 11472926Sek110237 spa_t *spa; 11482926Sek110237 char *hist_buf; 11492926Sek110237 uint64_t size; 11502926Sek110237 int error; 11512926Sek110237 11522926Sek110237 if ((size = zc->zc_history_len) == 0) 11532926Sek110237 return (EINVAL); 11542926Sek110237 11552926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 11562926Sek110237 return (error); 11572926Sek110237 11584577Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 11593863Sek110237 spa_close(spa, FTAG); 11603863Sek110237 return (ENOTSUP); 11613863Sek110237 } 11623863Sek110237 11632926Sek110237 hist_buf = kmem_alloc(size, KM_SLEEP); 11642926Sek110237 if ((error = spa_history_get(spa, &zc->zc_history_offset, 11652926Sek110237 &zc->zc_history_len, hist_buf)) == 0) { 11669643SEric.Taylor@Sun.COM error = ddi_copyout(hist_buf, 11679643SEric.Taylor@Sun.COM (void *)(uintptr_t)zc->zc_history, 11689643SEric.Taylor@Sun.COM zc->zc_history_len, zc->zc_iflags); 11692926Sek110237 } 11702926Sek110237 11712926Sek110237 spa_close(spa, FTAG); 11722926Sek110237 kmem_free(hist_buf, size); 11732926Sek110237 return (error); 11742926Sek110237 } 11752926Sek110237 11762926Sek110237 static int 11773444Sek110237 zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 11783444Sek110237 { 11793444Sek110237 int error; 11803444Sek110237 11813912Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 11823444Sek110237 return (error); 11833444Sek110237 11843444Sek110237 return (0); 11853444Sek110237 } 11863444Sek110237 1187*10298SMatthew.Ahrens@Sun.COM /* 1188*10298SMatthew.Ahrens@Sun.COM * inputs: 1189*10298SMatthew.Ahrens@Sun.COM * zc_name name of filesystem 1190*10298SMatthew.Ahrens@Sun.COM * zc_obj object to find 1191*10298SMatthew.Ahrens@Sun.COM * 1192*10298SMatthew.Ahrens@Sun.COM * outputs: 1193*10298SMatthew.Ahrens@Sun.COM * zc_value name of object 1194*10298SMatthew.Ahrens@Sun.COM */ 11953444Sek110237 static int 11963444Sek110237 zfs_ioc_obj_to_path(zfs_cmd_t *zc) 11973444Sek110237 { 1198*10298SMatthew.Ahrens@Sun.COM objset_t *os; 11993444Sek110237 int error; 12003444Sek110237 1201*10298SMatthew.Ahrens@Sun.COM /* XXX reading from objset not owned */ 1202*10298SMatthew.Ahrens@Sun.COM if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0) 12033444Sek110237 return (error); 1204*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_type(os) != DMU_OST_ZFS) { 1205*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 1206*10298SMatthew.Ahrens@Sun.COM return (EINVAL); 1207*10298SMatthew.Ahrens@Sun.COM } 1208*10298SMatthew.Ahrens@Sun.COM error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value, 12093444Sek110237 sizeof (zc->zc_value)); 1210*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 12113444Sek110237 12123444Sek110237 return (error); 12133444Sek110237 } 12143444Sek110237 12153444Sek110237 static int 1216789Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1217789Sahrens { 1218789Sahrens spa_t *spa; 1219789Sahrens int error; 12206423Sgw25295 nvlist_t *config, **l2cache, **spares; 12216423Sgw25295 uint_t nl2cache = 0, nspares = 0; 1222789Sahrens 1223789Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1224789Sahrens if (error != 0) 1225789Sahrens return (error); 1226789Sahrens 12275450Sbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 12289643SEric.Taylor@Sun.COM zc->zc_iflags, &config); 12295450Sbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 12305450Sbrendan &l2cache, &nl2cache); 12315450Sbrendan 12326423Sgw25295 (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 12336423Sgw25295 &spares, &nspares); 12346423Sgw25295 12353912Slling /* 12363912Slling * A root pool with concatenated devices is not supported. 12376423Sgw25295 * Thus, can not add a device to a root pool. 12386423Sgw25295 * 12396423Sgw25295 * Intent log device can not be added to a rootpool because 12406423Sgw25295 * during mountroot, zil is replayed, a seperated log device 12416423Sgw25295 * can not be accessed during the mountroot time. 12426423Sgw25295 * 12436423Sgw25295 * l2cache and spare devices are ok to be added to a rootpool. 12443912Slling */ 12456423Sgw25295 if (spa->spa_bootfs != 0 && nl2cache == 0 && nspares == 0) { 12463912Slling spa_close(spa, FTAG); 12473912Slling return (EDOM); 12483912Slling } 12493912Slling 12505450Sbrendan if (error == 0) { 1251789Sahrens error = spa_vdev_add(spa, config); 1252789Sahrens nvlist_free(config); 1253789Sahrens } 1254789Sahrens spa_close(spa, FTAG); 1255789Sahrens return (error); 1256789Sahrens } 1257789Sahrens 1258789Sahrens static int 1259789Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1260789Sahrens { 12612082Seschrock spa_t *spa; 12622082Seschrock int error; 12632082Seschrock 12642082Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 12652082Seschrock if (error != 0) 12662082Seschrock return (error); 12672082Seschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 12682082Seschrock spa_close(spa, FTAG); 12692082Seschrock return (error); 1270789Sahrens } 1271789Sahrens 1272789Sahrens static int 12734451Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1274789Sahrens { 1275789Sahrens spa_t *spa; 1276789Sahrens int error; 12774451Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1278789Sahrens 12792926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1280789Sahrens return (error); 12814451Seschrock switch (zc->zc_cookie) { 12824451Seschrock case VDEV_STATE_ONLINE: 12834451Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 12844451Seschrock break; 12854451Seschrock 12864451Seschrock case VDEV_STATE_OFFLINE: 12874451Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 12884451Seschrock break; 1289789Sahrens 12904451Seschrock case VDEV_STATE_FAULTED: 12914451Seschrock error = vdev_fault(spa, zc->zc_guid); 12924451Seschrock break; 1293789Sahrens 12944451Seschrock case VDEV_STATE_DEGRADED: 12954451Seschrock error = vdev_degrade(spa, zc->zc_guid); 12964451Seschrock break; 12974451Seschrock 12984451Seschrock default: 12994451Seschrock error = EINVAL; 13004451Seschrock } 13014451Seschrock zc->zc_cookie = newstate; 1302789Sahrens spa_close(spa, FTAG); 1303789Sahrens return (error); 1304789Sahrens } 1305789Sahrens 1306789Sahrens static int 1307789Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1308789Sahrens { 1309789Sahrens spa_t *spa; 1310789Sahrens int replacing = zc->zc_cookie; 1311789Sahrens nvlist_t *config; 1312789Sahrens int error; 1313789Sahrens 13142926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1315789Sahrens return (error); 1316789Sahrens 13175094Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 13189643SEric.Taylor@Sun.COM zc->zc_iflags, &config)) == 0) { 13191544Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1320789Sahrens nvlist_free(config); 1321789Sahrens } 1322789Sahrens 1323789Sahrens spa_close(spa, FTAG); 1324789Sahrens return (error); 1325789Sahrens } 1326789Sahrens 1327789Sahrens static int 1328789Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1329789Sahrens { 1330789Sahrens spa_t *spa; 1331789Sahrens int error; 1332789Sahrens 13332926Sek110237 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1334789Sahrens return (error); 1335789Sahrens 13368241SJeff.Bonwick@Sun.COM error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 1337789Sahrens 1338789Sahrens spa_close(spa, FTAG); 1339789Sahrens return (error); 1340789Sahrens } 1341789Sahrens 1342789Sahrens static int 13431354Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 13441354Seschrock { 13451354Seschrock spa_t *spa; 13462676Seschrock char *path = zc->zc_value; 13471544Seschrock uint64_t guid = zc->zc_guid; 13481354Seschrock int error; 13491354Seschrock 13501354Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 13511354Seschrock if (error != 0) 13521354Seschrock return (error); 13531354Seschrock 13541354Seschrock error = spa_vdev_setpath(spa, guid, path); 13551354Seschrock spa_close(spa, FTAG); 13561354Seschrock return (error); 13571354Seschrock } 13581354Seschrock 13599425SEric.Schrock@Sun.COM static int 13609425SEric.Schrock@Sun.COM zfs_ioc_vdev_setfru(zfs_cmd_t *zc) 13619425SEric.Schrock@Sun.COM { 13629425SEric.Schrock@Sun.COM spa_t *spa; 13639425SEric.Schrock@Sun.COM char *fru = zc->zc_value; 13649425SEric.Schrock@Sun.COM uint64_t guid = zc->zc_guid; 13659425SEric.Schrock@Sun.COM int error; 13669425SEric.Schrock@Sun.COM 13679425SEric.Schrock@Sun.COM error = spa_open(zc->zc_name, &spa, FTAG); 13689425SEric.Schrock@Sun.COM if (error != 0) 13699425SEric.Schrock@Sun.COM return (error); 13709425SEric.Schrock@Sun.COM 13719425SEric.Schrock@Sun.COM error = spa_vdev_setfru(spa, guid, fru); 13729425SEric.Schrock@Sun.COM spa_close(spa, FTAG); 13739425SEric.Schrock@Sun.COM return (error); 13749425SEric.Schrock@Sun.COM } 13759425SEric.Schrock@Sun.COM 13765367Sahrens /* 13775367Sahrens * inputs: 13785367Sahrens * zc_name name of filesystem 13795367Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13805367Sahrens * 13815367Sahrens * outputs: 13825367Sahrens * zc_objset_stats stats 13835367Sahrens * zc_nvlist_dst property nvlist 13845367Sahrens * zc_nvlist_dst_size size of property nvlist 13855367Sahrens */ 13861354Seschrock static int 1387789Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1388789Sahrens { 1389789Sahrens objset_t *os = NULL; 1390789Sahrens int error; 13911356Seschrock nvlist_t *nv; 1392789Sahrens 1393*10298SMatthew.Ahrens@Sun.COM if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1394789Sahrens return (error); 1395789Sahrens 13962885Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1397789Sahrens 13982856Snd150628 if (zc->zc_nvlist_dst != 0 && 13996689Smaybee (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 14002885Sahrens dmu_objset_stats(os, nv); 14013087Sahrens /* 14025147Srm160521 * NB: zvol_get_stats() will read the objset contents, 14033087Sahrens * which we aren't supposed to do with a 14046689Smaybee * DS_MODE_USER hold, because it could be 14053087Sahrens * inconsistent. So this is a bit of a workaround... 1406*10298SMatthew.Ahrens@Sun.COM * XXX reading with out owning 14073087Sahrens */ 14084577Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 14094577Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 14104577Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 14114577Sahrens } 14122676Seschrock error = put_nvlist(zc, nv); 14131356Seschrock nvlist_free(nv); 14141356Seschrock } 1415789Sahrens 1416*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 1417789Sahrens return (error); 1418789Sahrens } 1419789Sahrens 14205498Stimh static int 14215498Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 14225498Stimh { 14235498Stimh uint64_t value; 14245498Stimh int error; 14255498Stimh 14265498Stimh /* 14275498Stimh * zfs_get_zplprop() will either find a value or give us 14285498Stimh * the default value (if there is one). 14295498Stimh */ 14305498Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 14315498Stimh return (error); 14325498Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 14335498Stimh return (0); 14345498Stimh } 14355498Stimh 14365498Stimh /* 14375498Stimh * inputs: 14385498Stimh * zc_name name of filesystem 14395498Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 14405498Stimh * 14415498Stimh * outputs: 14425498Stimh * zc_nvlist_dst zpl property nvlist 14435498Stimh * zc_nvlist_dst_size size of zpl property nvlist 14445498Stimh */ 14455498Stimh static int 14465498Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 14475498Stimh { 14485498Stimh objset_t *os; 14495498Stimh int err; 14505498Stimh 1451*10298SMatthew.Ahrens@Sun.COM /* XXX reading without owning */ 1452*10298SMatthew.Ahrens@Sun.COM if (err = dmu_objset_hold(zc->zc_name, FTAG, &os)) 14535498Stimh return (err); 14545498Stimh 14555498Stimh dmu_objset_fast_stat(os, &zc->zc_objset_stats); 14565498Stimh 14575498Stimh /* 14585498Stimh * NB: nvl_add_zplprop() will read the objset contents, 14596689Smaybee * which we aren't supposed to do with a DS_MODE_USER 14606689Smaybee * hold, because it could be inconsistent. 14615498Stimh */ 14625498Stimh if (zc->zc_nvlist_dst != NULL && 14635498Stimh !zc->zc_objset_stats.dds_inconsistent && 14645498Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 14655498Stimh nvlist_t *nv; 14665498Stimh 14675498Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 14685498Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 14695498Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 14705498Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 14715498Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 14725498Stimh err = put_nvlist(zc, nv); 14735498Stimh nvlist_free(nv); 14745498Stimh } else { 14755498Stimh err = ENOENT; 14765498Stimh } 1477*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 14785498Stimh return (err); 14795498Stimh } 14805498Stimh 14819396SMatthew.Ahrens@Sun.COM static boolean_t 14829396SMatthew.Ahrens@Sun.COM dataset_name_hidden(const char *name) 14839396SMatthew.Ahrens@Sun.COM { 14849396SMatthew.Ahrens@Sun.COM /* 14859396SMatthew.Ahrens@Sun.COM * Skip over datasets that are not visible in this zone, 14869396SMatthew.Ahrens@Sun.COM * internal datasets (which have a $ in their name), and 14879396SMatthew.Ahrens@Sun.COM * temporary datasets (which have a % in their name). 14889396SMatthew.Ahrens@Sun.COM */ 14899396SMatthew.Ahrens@Sun.COM if (strchr(name, '$') != NULL) 14909396SMatthew.Ahrens@Sun.COM return (B_TRUE); 14919396SMatthew.Ahrens@Sun.COM if (strchr(name, '%') != NULL) 14929396SMatthew.Ahrens@Sun.COM return (B_TRUE); 14939396SMatthew.Ahrens@Sun.COM if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL)) 14949396SMatthew.Ahrens@Sun.COM return (B_TRUE); 14959396SMatthew.Ahrens@Sun.COM return (B_FALSE); 14969396SMatthew.Ahrens@Sun.COM } 14979396SMatthew.Ahrens@Sun.COM 14985367Sahrens /* 14995367Sahrens * inputs: 15005367Sahrens * zc_name name of filesystem 15015367Sahrens * zc_cookie zap cursor 15025367Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 15035367Sahrens * 15045367Sahrens * outputs: 15055367Sahrens * zc_name name of next filesystem 15069396SMatthew.Ahrens@Sun.COM * zc_cookie zap cursor 15075367Sahrens * zc_objset_stats stats 15085367Sahrens * zc_nvlist_dst property nvlist 15095367Sahrens * zc_nvlist_dst_size size of property nvlist 15105367Sahrens */ 1511789Sahrens static int 1512789Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1513789Sahrens { 1514885Sahrens objset_t *os; 1515789Sahrens int error; 1516789Sahrens char *p; 1517789Sahrens 1518*10298SMatthew.Ahrens@Sun.COM if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) { 1519885Sahrens if (error == ENOENT) 1520885Sahrens error = ESRCH; 1521885Sahrens return (error); 1522789Sahrens } 1523789Sahrens 1524789Sahrens p = strrchr(zc->zc_name, '/'); 1525789Sahrens if (p == NULL || p[1] != '\0') 1526789Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1527789Sahrens p = zc->zc_name + strlen(zc->zc_name); 1528789Sahrens 15298697SRichard.Morris@Sun.COM /* 15308697SRichard.Morris@Sun.COM * Pre-fetch the datasets. dmu_objset_prefetch() always returns 0 15318697SRichard.Morris@Sun.COM * but is not declared void because its called by dmu_objset_find(). 15328697SRichard.Morris@Sun.COM */ 15338415SRichard.Morris@Sun.COM if (zc->zc_cookie == 0) { 15348415SRichard.Morris@Sun.COM uint64_t cookie = 0; 15358415SRichard.Morris@Sun.COM int len = sizeof (zc->zc_name) - (p - zc->zc_name); 15368415SRichard.Morris@Sun.COM 15378415SRichard.Morris@Sun.COM while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) 15388697SRichard.Morris@Sun.COM (void) dmu_objset_prefetch(p, NULL); 15398415SRichard.Morris@Sun.COM } 15408415SRichard.Morris@Sun.COM 1541789Sahrens do { 1542885Sahrens error = dmu_dir_list_next(os, 1543885Sahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 1544885Sahrens NULL, &zc->zc_cookie); 1545789Sahrens if (error == ENOENT) 1546789Sahrens error = ESRCH; 15479396SMatthew.Ahrens@Sun.COM } while (error == 0 && dataset_name_hidden(zc->zc_name)); 1548*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 1549789Sahrens 15509396SMatthew.Ahrens@Sun.COM if (error == 0) 1551885Sahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1552789Sahrens 1553789Sahrens return (error); 1554789Sahrens } 1555789Sahrens 15565367Sahrens /* 15575367Sahrens * inputs: 15585367Sahrens * zc_name name of filesystem 15595367Sahrens * zc_cookie zap cursor 15605367Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 15615367Sahrens * 15625367Sahrens * outputs: 15635367Sahrens * zc_name name of next snapshot 15645367Sahrens * zc_objset_stats stats 15655367Sahrens * zc_nvlist_dst property nvlist 15665367Sahrens * zc_nvlist_dst_size size of property nvlist 15675367Sahrens */ 1568789Sahrens static int 1569789Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1570789Sahrens { 1571885Sahrens objset_t *os; 1572789Sahrens int error; 1573789Sahrens 1574*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(zc->zc_name, FTAG, &os); 15756689Smaybee if (error) 15766689Smaybee return (error == ENOENT ? ESRCH : error); 1577789Sahrens 15789396SMatthew.Ahrens@Sun.COM if (zc->zc_cookie == 0) { 15798697SRichard.Morris@Sun.COM (void) dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 15808415SRichard.Morris@Sun.COM NULL, DS_FIND_SNAPSHOTS); 15819396SMatthew.Ahrens@Sun.COM } 15821003Slling /* 15831003Slling * A dataset name of maximum length cannot have any snapshots, 15841003Slling * so exit immediately. 15851003Slling */ 15861003Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 1587*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 15881003Slling return (ESRCH); 1589789Sahrens } 1590789Sahrens 1591885Sahrens error = dmu_snapshot_list_next(os, 1592885Sahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 15935663Sck153898 zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 1594*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 1595885Sahrens if (error == 0) 1596885Sahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 15976689Smaybee else if (error == ENOENT) 15986689Smaybee error = ESRCH; 1599789Sahrens 16005367Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 16016689Smaybee if (error) 16025367Sahrens *strchr(zc->zc_name, '@') = '\0'; 1603789Sahrens return (error); 1604789Sahrens } 1605789Sahrens 16066423Sgw25295 int 16074787Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1608789Sahrens { 16092676Seschrock nvpair_t *elem; 16108724SRichard.Morris@Sun.COM int error = 0; 16112676Seschrock uint64_t intval; 16122676Seschrock char *strval; 16138697SRichard.Morris@Sun.COM nvlist_t *genericnvl; 16149396SMatthew.Ahrens@Sun.COM boolean_t issnap = (strchr(name, '@') != NULL); 16152676Seschrock 16164543Smarks /* 16174543Smarks * First validate permission to set all of the properties 16184543Smarks */ 16192676Seschrock elem = NULL; 16202676Seschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 16214670Sahrens const char *propname = nvpair_name(elem); 16224670Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 16232676Seschrock 16245094Slling if (prop == ZPROP_INVAL) { 16252676Seschrock /* 16262676Seschrock * If this is a user-defined property, it must be a 16272676Seschrock * string, and there is no further validation to do. 16282676Seschrock */ 16299396SMatthew.Ahrens@Sun.COM if (zfs_prop_user(propname) && 16309396SMatthew.Ahrens@Sun.COM nvpair_type(elem) == DATA_TYPE_STRING) { 16319396SMatthew.Ahrens@Sun.COM if (error = zfs_secpolicy_write_perms(name, 16329396SMatthew.Ahrens@Sun.COM ZFS_DELEG_PERM_USERPROP, CRED())) 16339396SMatthew.Ahrens@Sun.COM return (error); 16349396SMatthew.Ahrens@Sun.COM continue; 16359396SMatthew.Ahrens@Sun.COM } 16369396SMatthew.Ahrens@Sun.COM 16379396SMatthew.Ahrens@Sun.COM if (!issnap && zfs_prop_userquota(propname) && 16389396SMatthew.Ahrens@Sun.COM nvpair_type(elem) == DATA_TYPE_UINT64_ARRAY) { 16399396SMatthew.Ahrens@Sun.COM const char *perm; 16409396SMatthew.Ahrens@Sun.COM const char *up = zfs_userquota_prop_prefixes 16419396SMatthew.Ahrens@Sun.COM [ZFS_PROP_USERQUOTA]; 16429396SMatthew.Ahrens@Sun.COM if (strncmp(propname, up, strlen(up)) == 0) 16439396SMatthew.Ahrens@Sun.COM perm = ZFS_DELEG_PERM_USERQUOTA; 16449396SMatthew.Ahrens@Sun.COM else 16459396SMatthew.Ahrens@Sun.COM perm = ZFS_DELEG_PERM_GROUPQUOTA; 16469396SMatthew.Ahrens@Sun.COM if (error = zfs_secpolicy_write_perms(name, 16479396SMatthew.Ahrens@Sun.COM perm, CRED())) 16489396SMatthew.Ahrens@Sun.COM return (error); 16499396SMatthew.Ahrens@Sun.COM continue; 16509396SMatthew.Ahrens@Sun.COM } 16519396SMatthew.Ahrens@Sun.COM 16529396SMatthew.Ahrens@Sun.COM return (EINVAL); 16532676Seschrock } 16542676Seschrock 16559396SMatthew.Ahrens@Sun.COM if (issnap) 16569396SMatthew.Ahrens@Sun.COM return (EINVAL); 16579396SMatthew.Ahrens@Sun.COM 16584787Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 16594670Sahrens return (error); 16602676Seschrock 16614670Sahrens /* 16624670Sahrens * Check that this value is valid for this pool version 16634670Sahrens */ 16644670Sahrens switch (prop) { 16653886Sahl case ZFS_PROP_COMPRESSION: 16663886Sahl /* 16673886Sahl * If the user specified gzip compression, make sure 16683886Sahl * the SPA supports it. We ignore any errors here since 16693886Sahl * we'll catch them later. 16703886Sahl */ 16713886Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 16727042Sgw25295 nvpair_value_uint64(elem, &intval) == 0) { 16737042Sgw25295 if (intval >= ZIO_COMPRESS_GZIP_1 && 16747042Sgw25295 intval <= ZIO_COMPRESS_GZIP_9 && 16757184Stimh zfs_earlier_version(name, 16765331Samw SPA_VERSION_GZIP_COMPRESSION)) 16775331Samw return (ENOTSUP); 16787042Sgw25295 16797042Sgw25295 /* 16807042Sgw25295 * If this is a bootable dataset then 16817042Sgw25295 * verify that the compression algorithm 16827042Sgw25295 * is supported for booting. We must return 16837042Sgw25295 * something other than ENOTSUP since it 16847042Sgw25295 * implies a downrev pool version. 16857042Sgw25295 */ 16867042Sgw25295 if (zfs_is_bootfs(name) && 16877042Sgw25295 !BOOTFS_COMPRESS_VALID(intval)) 16887042Sgw25295 return (ERANGE); 16893886Sahl } 16903886Sahl break; 16914603Sahrens 16924603Sahrens case ZFS_PROP_COPIES: 16939396SMatthew.Ahrens@Sun.COM if (zfs_earlier_version(name, SPA_VERSION_DITTO_BLOCKS)) 16945331Samw return (ENOTSUP); 16954603Sahrens break; 16965977Smarks 16975977Smarks case ZFS_PROP_SHARESMB: 16986689Smaybee if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 16995977Smarks return (ENOTSUP); 17005977Smarks break; 17018053SMark.Shellenbaum@Sun.COM 17028053SMark.Shellenbaum@Sun.COM case ZFS_PROP_ACLINHERIT: 17038053SMark.Shellenbaum@Sun.COM if (nvpair_type(elem) == DATA_TYPE_UINT64 && 17048053SMark.Shellenbaum@Sun.COM nvpair_value_uint64(elem, &intval) == 0) 17058053SMark.Shellenbaum@Sun.COM if (intval == ZFS_ACL_PASSTHROUGH_X && 17068053SMark.Shellenbaum@Sun.COM zfs_earlier_version(name, 17078053SMark.Shellenbaum@Sun.COM SPA_VERSION_PASSTHROUGH_X)) 17088053SMark.Shellenbaum@Sun.COM return (ENOTSUP); 17094603Sahrens } 17104543Smarks } 17114543Smarks 17128697SRichard.Morris@Sun.COM VERIFY(nvlist_alloc(&genericnvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 17134543Smarks elem = NULL; 17144543Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 17154670Sahrens const char *propname = nvpair_name(elem); 17164670Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 17174543Smarks 17185094Slling if (prop == ZPROP_INVAL) { 17199396SMatthew.Ahrens@Sun.COM if (zfs_prop_userquota(propname)) { 17209396SMatthew.Ahrens@Sun.COM uint64_t *valary; 17219396SMatthew.Ahrens@Sun.COM unsigned int vallen; 17229396SMatthew.Ahrens@Sun.COM const char *domain; 17239396SMatthew.Ahrens@Sun.COM zfs_userquota_prop_t type; 17249396SMatthew.Ahrens@Sun.COM uint64_t rid; 17259396SMatthew.Ahrens@Sun.COM uint64_t quota; 17269396SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs; 17279396SMatthew.Ahrens@Sun.COM 17289396SMatthew.Ahrens@Sun.COM VERIFY(nvpair_value_uint64_array(elem, 17299396SMatthew.Ahrens@Sun.COM &valary, &vallen) == 0); 17309396SMatthew.Ahrens@Sun.COM VERIFY(vallen == 3); 17319396SMatthew.Ahrens@Sun.COM type = valary[0]; 17329396SMatthew.Ahrens@Sun.COM rid = valary[1]; 17339396SMatthew.Ahrens@Sun.COM quota = valary[2]; 17349396SMatthew.Ahrens@Sun.COM domain = propname + 17359396SMatthew.Ahrens@Sun.COM strlen(zfs_userquota_prop_prefixes[type]); 17369396SMatthew.Ahrens@Sun.COM 1737*10298SMatthew.Ahrens@Sun.COM error = zfsvfs_hold(name, FTAG, &zfsvfs); 17389396SMatthew.Ahrens@Sun.COM if (error == 0) { 17399396SMatthew.Ahrens@Sun.COM error = zfs_set_userquota(zfsvfs, 17409396SMatthew.Ahrens@Sun.COM type, domain, rid, quota); 17419396SMatthew.Ahrens@Sun.COM zfsvfs_rele(zfsvfs, FTAG); 17429396SMatthew.Ahrens@Sun.COM } 17439396SMatthew.Ahrens@Sun.COM if (error == 0) 17449396SMatthew.Ahrens@Sun.COM continue; 17459396SMatthew.Ahrens@Sun.COM else 17469396SMatthew.Ahrens@Sun.COM goto out; 17479396SMatthew.Ahrens@Sun.COM } else if (zfs_prop_user(propname)) { 17489396SMatthew.Ahrens@Sun.COM VERIFY(nvpair_value_string(elem, &strval) == 0); 17499396SMatthew.Ahrens@Sun.COM error = dsl_prop_set(name, propname, 1, 17509396SMatthew.Ahrens@Sun.COM strlen(strval) + 1, strval); 17519396SMatthew.Ahrens@Sun.COM if (error == 0) 17529396SMatthew.Ahrens@Sun.COM continue; 17539396SMatthew.Ahrens@Sun.COM else 17549396SMatthew.Ahrens@Sun.COM goto out; 17559396SMatthew.Ahrens@Sun.COM } 17564543Smarks } 17572676Seschrock 17582676Seschrock switch (prop) { 17592676Seschrock case ZFS_PROP_QUOTA: 17602676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 17614577Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 17628697SRichard.Morris@Sun.COM goto out; 17632676Seschrock break; 17642676Seschrock 17655378Sck153898 case ZFS_PROP_REFQUOTA: 17665378Sck153898 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 17675378Sck153898 (error = dsl_dataset_set_quota(name, intval)) != 0) 17688697SRichard.Morris@Sun.COM goto out; 17695378Sck153898 break; 17705378Sck153898 17712676Seschrock case ZFS_PROP_RESERVATION: 17722676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 17732676Seschrock (error = dsl_dir_set_reservation(name, 17742676Seschrock intval)) != 0) 17758697SRichard.Morris@Sun.COM goto out; 17762676Seschrock break; 1777789Sahrens 17785378Sck153898 case ZFS_PROP_REFRESERVATION: 17795378Sck153898 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 17805378Sck153898 (error = dsl_dataset_set_reservation(name, 17815378Sck153898 intval)) != 0) 17828697SRichard.Morris@Sun.COM goto out; 17835378Sck153898 break; 17845378Sck153898 17852676Seschrock case ZFS_PROP_VOLSIZE: 17862676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 17874787Sahrens (error = zvol_set_volsize(name, 17884787Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 17898697SRichard.Morris@Sun.COM goto out; 17902676Seschrock break; 17912676Seschrock 17922676Seschrock case ZFS_PROP_VOLBLOCKSIZE: 17932676Seschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 17944577Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 17958697SRichard.Morris@Sun.COM goto out; 17964577Sahrens break; 17974577Sahrens 17984577Sahrens case ZFS_PROP_VERSION: 17999396SMatthew.Ahrens@Sun.COM { 18009396SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs; 18019396SMatthew.Ahrens@Sun.COM 18029396SMatthew.Ahrens@Sun.COM if ((error = nvpair_value_uint64(elem, &intval)) != 0) 18039396SMatthew.Ahrens@Sun.COM goto out; 1804*10298SMatthew.Ahrens@Sun.COM if ((error = zfsvfs_hold(name, FTAG, &zfsvfs)) != 0) 18059396SMatthew.Ahrens@Sun.COM goto out; 18069396SMatthew.Ahrens@Sun.COM error = zfs_set_version(zfsvfs, intval); 18079396SMatthew.Ahrens@Sun.COM zfsvfs_rele(zfsvfs, FTAG); 18089396SMatthew.Ahrens@Sun.COM 18099396SMatthew.Ahrens@Sun.COM if (error == 0 && intval >= ZPL_VERSION_USERSPACE) { 18109396SMatthew.Ahrens@Sun.COM zfs_cmd_t zc = { 0 }; 18119396SMatthew.Ahrens@Sun.COM (void) strcpy(zc.zc_name, name); 18129396SMatthew.Ahrens@Sun.COM (void) zfs_ioc_userspace_upgrade(&zc); 18139396SMatthew.Ahrens@Sun.COM } 18149396SMatthew.Ahrens@Sun.COM if (error) 18158697SRichard.Morris@Sun.COM goto out; 18162676Seschrock break; 18179396SMatthew.Ahrens@Sun.COM } 18182676Seschrock 18192676Seschrock default: 18202676Seschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 18212676Seschrock if (zfs_prop_get_type(prop) != 18228697SRichard.Morris@Sun.COM PROP_TYPE_STRING) { 18238697SRichard.Morris@Sun.COM error = EINVAL; 18248697SRichard.Morris@Sun.COM goto out; 18258697SRichard.Morris@Sun.COM } 18262676Seschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 18272885Sahrens const char *unused; 18282885Sahrens 18292717Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 18302676Seschrock 18312676Seschrock switch (zfs_prop_get_type(prop)) { 18324787Sahrens case PROP_TYPE_NUMBER: 18332676Seschrock break; 18344787Sahrens case PROP_TYPE_STRING: 18358697SRichard.Morris@Sun.COM error = EINVAL; 18368697SRichard.Morris@Sun.COM goto out; 18374787Sahrens case PROP_TYPE_INDEX: 18382717Seschrock if (zfs_prop_index_to_string(prop, 18398697SRichard.Morris@Sun.COM intval, &unused) != 0) { 18408697SRichard.Morris@Sun.COM error = EINVAL; 18418697SRichard.Morris@Sun.COM goto out; 18428697SRichard.Morris@Sun.COM } 18432676Seschrock break; 18442676Seschrock default: 18454577Sahrens cmn_err(CE_PANIC, 18464577Sahrens "unknown property type"); 18472676Seschrock break; 18482676Seschrock } 18492676Seschrock } else { 18508697SRichard.Morris@Sun.COM error = EINVAL; 18518697SRichard.Morris@Sun.COM goto out; 18522676Seschrock } 18538697SRichard.Morris@Sun.COM if ((error = nvlist_add_nvpair(genericnvl, elem)) != 0) 18548697SRichard.Morris@Sun.COM goto out; 18552676Seschrock } 18562676Seschrock } 18572676Seschrock 18588697SRichard.Morris@Sun.COM if (nvlist_next_nvpair(genericnvl, NULL) != NULL) { 18598697SRichard.Morris@Sun.COM error = dsl_props_set(name, genericnvl); 18608697SRichard.Morris@Sun.COM } 18618697SRichard.Morris@Sun.COM out: 18628697SRichard.Morris@Sun.COM nvlist_free(genericnvl); 18638697SRichard.Morris@Sun.COM return (error); 1864789Sahrens } 1865789Sahrens 18665367Sahrens /* 18679355SMatthew.Ahrens@Sun.COM * Check that all the properties are valid user properties. 18689355SMatthew.Ahrens@Sun.COM */ 18699355SMatthew.Ahrens@Sun.COM static int 18709355SMatthew.Ahrens@Sun.COM zfs_check_userprops(char *fsname, nvlist_t *nvl) 18719355SMatthew.Ahrens@Sun.COM { 18729355SMatthew.Ahrens@Sun.COM nvpair_t *elem = NULL; 18739355SMatthew.Ahrens@Sun.COM int error = 0; 18749355SMatthew.Ahrens@Sun.COM 18759355SMatthew.Ahrens@Sun.COM while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 18769355SMatthew.Ahrens@Sun.COM const char *propname = nvpair_name(elem); 18779355SMatthew.Ahrens@Sun.COM char *valstr; 18789355SMatthew.Ahrens@Sun.COM 18799355SMatthew.Ahrens@Sun.COM if (!zfs_prop_user(propname) || 18809355SMatthew.Ahrens@Sun.COM nvpair_type(elem) != DATA_TYPE_STRING) 18819355SMatthew.Ahrens@Sun.COM return (EINVAL); 18829355SMatthew.Ahrens@Sun.COM 18839355SMatthew.Ahrens@Sun.COM if (error = zfs_secpolicy_write_perms(fsname, 18849355SMatthew.Ahrens@Sun.COM ZFS_DELEG_PERM_USERPROP, CRED())) 18859355SMatthew.Ahrens@Sun.COM return (error); 18869355SMatthew.Ahrens@Sun.COM 18879355SMatthew.Ahrens@Sun.COM if (strlen(propname) >= ZAP_MAXNAMELEN) 18889355SMatthew.Ahrens@Sun.COM return (ENAMETOOLONG); 18899355SMatthew.Ahrens@Sun.COM 18909355SMatthew.Ahrens@Sun.COM VERIFY(nvpair_value_string(elem, &valstr) == 0); 18919355SMatthew.Ahrens@Sun.COM if (strlen(valstr) >= ZAP_MAXVALUELEN) 18929355SMatthew.Ahrens@Sun.COM return (E2BIG); 18939355SMatthew.Ahrens@Sun.COM } 18949355SMatthew.Ahrens@Sun.COM return (0); 18959355SMatthew.Ahrens@Sun.COM } 18969355SMatthew.Ahrens@Sun.COM 18979355SMatthew.Ahrens@Sun.COM /* 18985367Sahrens * inputs: 18995367Sahrens * zc_name name of filesystem 19008697SRichard.Morris@Sun.COM * zc_value name of property to set 19015367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 19027265Sahrens * zc_cookie clear existing local props? 19035367Sahrens * 19045367Sahrens * outputs: none 19055367Sahrens */ 1906789Sahrens static int 19072676Seschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1908789Sahrens { 19092676Seschrock nvlist_t *nvl; 19102676Seschrock int error; 1911789Sahrens 19125094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 19139643SEric.Taylor@Sun.COM zc->zc_iflags, &nvl)) != 0) 19142676Seschrock return (error); 19152676Seschrock 19167265Sahrens if (zc->zc_cookie) { 19177265Sahrens nvlist_t *origprops; 19187265Sahrens objset_t *os; 19197265Sahrens 1920*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_hold(zc->zc_name, FTAG, &os) == 0) { 19217265Sahrens if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 19228536SDavid.Pacheco@Sun.COM clear_props(zc->zc_name, origprops, nvl); 19237265Sahrens nvlist_free(origprops); 19247265Sahrens } 1925*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 19267265Sahrens } 19277265Sahrens 19287265Sahrens } 19297265Sahrens 19304787Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 19314543Smarks 19322676Seschrock nvlist_free(nvl); 19332676Seschrock return (error); 1934789Sahrens } 1935789Sahrens 19365367Sahrens /* 19375367Sahrens * inputs: 19385367Sahrens * zc_name name of filesystem 19395367Sahrens * zc_value name of property to inherit 19405367Sahrens * 19415367Sahrens * outputs: none 19425367Sahrens */ 1943789Sahrens static int 19444849Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 19454849Sahrens { 19464849Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 19474849Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 19484849Sahrens } 19494849Sahrens 19504849Sahrens static int 19514098Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 19523912Slling { 19535094Slling nvlist_t *props; 19543912Slling spa_t *spa; 19555094Slling int error; 19568525SEric.Schrock@Sun.COM nvpair_t *elem; 19573912Slling 19585094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 19599643SEric.Taylor@Sun.COM zc->zc_iflags, &props))) 19603912Slling return (error); 19613912Slling 19628525SEric.Schrock@Sun.COM /* 19638525SEric.Schrock@Sun.COM * If the only property is the configfile, then just do a spa_lookup() 19648525SEric.Schrock@Sun.COM * to handle the faulted case. 19658525SEric.Schrock@Sun.COM */ 19668525SEric.Schrock@Sun.COM elem = nvlist_next_nvpair(props, NULL); 19678525SEric.Schrock@Sun.COM if (elem != NULL && strcmp(nvpair_name(elem), 19688525SEric.Schrock@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 19698525SEric.Schrock@Sun.COM nvlist_next_nvpair(props, elem) == NULL) { 19708525SEric.Schrock@Sun.COM mutex_enter(&spa_namespace_lock); 19718525SEric.Schrock@Sun.COM if ((spa = spa_lookup(zc->zc_name)) != NULL) { 19728525SEric.Schrock@Sun.COM spa_configfile_set(spa, props, B_FALSE); 19738525SEric.Schrock@Sun.COM spa_config_sync(spa, B_FALSE, B_TRUE); 19748525SEric.Schrock@Sun.COM } 19758525SEric.Schrock@Sun.COM mutex_exit(&spa_namespace_lock); 19768525SEric.Schrock@Sun.COM if (spa != NULL) 19778525SEric.Schrock@Sun.COM return (0); 19788525SEric.Schrock@Sun.COM } 19798525SEric.Schrock@Sun.COM 19803912Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 19815094Slling nvlist_free(props); 19823912Slling return (error); 19833912Slling } 19843912Slling 19855094Slling error = spa_prop_set(spa, props); 19863912Slling 19875094Slling nvlist_free(props); 19883912Slling spa_close(spa, FTAG); 19893912Slling 19903912Slling return (error); 19913912Slling } 19923912Slling 19933912Slling static int 19944098Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 19953912Slling { 19963912Slling spa_t *spa; 19973912Slling int error; 19983912Slling nvlist_t *nvp = NULL; 19993912Slling 20008525SEric.Schrock@Sun.COM if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 20018525SEric.Schrock@Sun.COM /* 20028525SEric.Schrock@Sun.COM * If the pool is faulted, there may be properties we can still 20038525SEric.Schrock@Sun.COM * get (such as altroot and cachefile), so attempt to get them 20048525SEric.Schrock@Sun.COM * anyway. 20058525SEric.Schrock@Sun.COM */ 20068525SEric.Schrock@Sun.COM mutex_enter(&spa_namespace_lock); 20078525SEric.Schrock@Sun.COM if ((spa = spa_lookup(zc->zc_name)) != NULL) 20088525SEric.Schrock@Sun.COM error = spa_prop_get(spa, &nvp); 20098525SEric.Schrock@Sun.COM mutex_exit(&spa_namespace_lock); 20108525SEric.Schrock@Sun.COM } else { 20118525SEric.Schrock@Sun.COM error = spa_prop_get(spa, &nvp); 20128525SEric.Schrock@Sun.COM spa_close(spa, FTAG); 20138525SEric.Schrock@Sun.COM } 20143912Slling 20153912Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 20163912Slling error = put_nvlist(zc, nvp); 20173912Slling else 20183912Slling error = EFAULT; 20193912Slling 20208525SEric.Schrock@Sun.COM nvlist_free(nvp); 20213912Slling return (error); 20223912Slling } 20233912Slling 20243912Slling static int 20254543Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 20264543Smarks { 20274543Smarks nvlist_t *nvp; 20284543Smarks int error; 20294543Smarks uint32_t uid; 20304543Smarks uint32_t gid; 20314543Smarks uint32_t *groups; 20324543Smarks uint_t group_cnt; 20334543Smarks cred_t *usercred; 20344543Smarks 20355094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 20369643SEric.Taylor@Sun.COM zc->zc_iflags, &nvp)) != 0) { 20374543Smarks return (error); 20384543Smarks } 20394543Smarks 20404543Smarks if ((error = nvlist_lookup_uint32(nvp, 20414543Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 20424543Smarks nvlist_free(nvp); 20434543Smarks return (EPERM); 20444543Smarks } 20454543Smarks 20464543Smarks if ((error = nvlist_lookup_uint32(nvp, 20474543Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 20484543Smarks nvlist_free(nvp); 20494543Smarks return (EPERM); 20504543Smarks } 20514543Smarks 20524543Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 20534543Smarks &groups, &group_cnt)) != 0) { 20544543Smarks nvlist_free(nvp); 20554543Smarks return (EPERM); 20564543Smarks } 20574543Smarks usercred = cralloc(); 20584543Smarks if ((crsetugid(usercred, uid, gid) != 0) || 20594543Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 20604543Smarks nvlist_free(nvp); 20614543Smarks crfree(usercred); 20624543Smarks return (EPERM); 20634543Smarks } 20644543Smarks nvlist_free(nvp); 20654543Smarks error = dsl_deleg_access(zc->zc_name, 20664787Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 20674543Smarks crfree(usercred); 20684543Smarks return (error); 20694543Smarks } 20704543Smarks 20715367Sahrens /* 20725367Sahrens * inputs: 20735367Sahrens * zc_name name of filesystem 20745367Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 20755367Sahrens * zc_perm_action allow/unallow flag 20765367Sahrens * 20775367Sahrens * outputs: none 20785367Sahrens */ 20794543Smarks static int 20804543Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 20814543Smarks { 20824543Smarks int error; 20834543Smarks nvlist_t *fsaclnv = NULL; 20844543Smarks 20855094Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 20869643SEric.Taylor@Sun.COM zc->zc_iflags, &fsaclnv)) != 0) 20874543Smarks return (error); 20884543Smarks 20894543Smarks /* 20904543Smarks * Verify nvlist is constructed correctly 20914543Smarks */ 20924543Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 20934543Smarks nvlist_free(fsaclnv); 20944543Smarks return (EINVAL); 20954543Smarks } 20964543Smarks 20974543Smarks /* 20984543Smarks * If we don't have PRIV_SYS_MOUNT, then validate 20994543Smarks * that user is allowed to hand out each permission in 21004543Smarks * the nvlist(s) 21014543Smarks */ 21024543Smarks 21034787Sahrens error = secpolicy_zfs(CRED()); 21044543Smarks if (error) { 21054787Sahrens if (zc->zc_perm_action == B_FALSE) { 21064787Sahrens error = dsl_deleg_can_allow(zc->zc_name, 21074787Sahrens fsaclnv, CRED()); 21084787Sahrens } else { 21094787Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 21104787Sahrens fsaclnv, CRED()); 21114787Sahrens } 21124543Smarks } 21134543Smarks 21144543Smarks if (error == 0) 21154543Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 21164543Smarks 21174543Smarks nvlist_free(fsaclnv); 21184543Smarks return (error); 21194543Smarks } 21204543Smarks 21215367Sahrens /* 21225367Sahrens * inputs: 21235367Sahrens * zc_name name of filesystem 21245367Sahrens * 21255367Sahrens * outputs: 21265367Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 21275367Sahrens */ 21284543Smarks static int 21294543Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 21304543Smarks { 21314543Smarks nvlist_t *nvp; 21324543Smarks int error; 21334543Smarks 21344543Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 21354543Smarks error = put_nvlist(zc, nvp); 21364543Smarks nvlist_free(nvp); 21374543Smarks } 21384543Smarks 21394543Smarks return (error); 21404543Smarks } 21414543Smarks 21425367Sahrens /* 21435367Sahrens * inputs: 21445367Sahrens * zc_name name of volume 21455367Sahrens * 21465367Sahrens * outputs: none 21475367Sahrens */ 21484543Smarks static int 2149789Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 2150789Sahrens { 21514787Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 2152789Sahrens } 2153789Sahrens 21545367Sahrens /* 21555367Sahrens * inputs: 21565367Sahrens * zc_name name of volume 21575367Sahrens * 21585367Sahrens * outputs: none 21595367Sahrens */ 2160789Sahrens static int 2161789Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 2162789Sahrens { 21632676Seschrock return (zvol_remove_minor(zc->zc_name)); 2164789Sahrens } 2165789Sahrens 2166789Sahrens /* 2167789Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 2168789Sahrens * or NULL if no suitable entry is found. The caller of this routine 2169789Sahrens * is responsible for releasing the returned vfs pointer. 2170789Sahrens */ 2171789Sahrens static vfs_t * 2172789Sahrens zfs_get_vfs(const char *resource) 2173789Sahrens { 2174789Sahrens struct vfs *vfsp; 2175789Sahrens struct vfs *vfs_found = NULL; 2176789Sahrens 2177789Sahrens vfs_list_read_lock(); 2178789Sahrens vfsp = rootvfs; 2179789Sahrens do { 2180789Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 2181789Sahrens VFS_HOLD(vfsp); 2182789Sahrens vfs_found = vfsp; 2183789Sahrens break; 2184789Sahrens } 2185789Sahrens vfsp = vfsp->vfs_next; 2186789Sahrens } while (vfsp != rootvfs); 2187789Sahrens vfs_list_unlock(); 2188789Sahrens return (vfs_found); 2189789Sahrens } 2190789Sahrens 21914543Smarks /* ARGSUSED */ 2192789Sahrens static void 21934543Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 2194789Sahrens { 21955331Samw zfs_creat_t *zct = arg; 21965498Stimh 21975498Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 21985331Samw } 21995331Samw 22005498Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 22015498Stimh 22025331Samw /* 22035498Stimh * inputs: 22047184Stimh * createprops list of properties requested by creator 22057184Stimh * default_zplver zpl version to use if unspecified in createprops 22067184Stimh * fuids_ok fuids allowed in this version of the spa? 22077184Stimh * os parent objset pointer (NULL if root fs) 22085331Samw * 22095498Stimh * outputs: 22105498Stimh * zplprops values for the zplprops we attach to the master node object 22117184Stimh * is_ci true if requested file system will be purely case-insensitive 22125331Samw * 22135498Stimh * Determine the settings for utf8only, normalization and 22145498Stimh * casesensitivity. Specific values may have been requested by the 22155498Stimh * creator and/or we can inherit values from the parent dataset. If 22165498Stimh * the file system is of too early a vintage, a creator can not 22175498Stimh * request settings for these properties, even if the requested 22185498Stimh * setting is the default value. We don't actually want to create dsl 22195498Stimh * properties for these, so remove them from the source nvlist after 22205498Stimh * processing. 22215331Samw */ 22225331Samw static int 22239396SMatthew.Ahrens@Sun.COM zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 22247184Stimh boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 22257184Stimh boolean_t *is_ci) 22265331Samw { 22275498Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 22285498Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 22295498Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 22305498Stimh 22315498Stimh ASSERT(zplprops != NULL); 22325498Stimh 22335375Stimh /* 22345498Stimh * Pull out creator prop choices, if any. 22355375Stimh */ 22365498Stimh if (createprops) { 22375498Stimh (void) nvlist_lookup_uint64(createprops, 22387184Stimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 22397184Stimh (void) nvlist_lookup_uint64(createprops, 22405498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 22415498Stimh (void) nvlist_remove_all(createprops, 22425498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 22435498Stimh (void) nvlist_lookup_uint64(createprops, 22445498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 22455498Stimh (void) nvlist_remove_all(createprops, 22465498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 22475498Stimh (void) nvlist_lookup_uint64(createprops, 22485498Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 22495498Stimh (void) nvlist_remove_all(createprops, 22505498Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 22515331Samw } 22525331Samw 22535375Stimh /* 22547184Stimh * If the zpl version requested is whacky or the file system 22557184Stimh * or pool is version is too "young" to support normalization 22567184Stimh * and the creator tried to set a value for one of the props, 22577184Stimh * error out. 22585498Stimh */ 22597184Stimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 22607184Stimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 22617184Stimh (zplver < ZPL_VERSION_NORMALIZATION && 22625498Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 22637184Stimh sense != ZFS_PROP_UNDEFINED))) 22645498Stimh return (ENOTSUP); 22655498Stimh 22665498Stimh /* 22675498Stimh * Put the version in the zplprops 22685498Stimh */ 22695498Stimh VERIFY(nvlist_add_uint64(zplprops, 22705498Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 22715498Stimh 22725498Stimh if (norm == ZFS_PROP_UNDEFINED) 22735498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 22745498Stimh VERIFY(nvlist_add_uint64(zplprops, 22755498Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 22765498Stimh 22775498Stimh /* 22785498Stimh * If we're normalizing, names must always be valid UTF-8 strings. 22795498Stimh */ 22805498Stimh if (norm) 22815498Stimh u8 = 1; 22825498Stimh if (u8 == ZFS_PROP_UNDEFINED) 22835498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 22845498Stimh VERIFY(nvlist_add_uint64(zplprops, 22855498Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 22865498Stimh 22875498Stimh if (sense == ZFS_PROP_UNDEFINED) 22885498Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 22895498Stimh VERIFY(nvlist_add_uint64(zplprops, 22905498Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 22915498Stimh 22926492Stimh if (is_ci) 22936492Stimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 22946492Stimh 22957184Stimh return (0); 22967184Stimh } 22977184Stimh 22987184Stimh static int 22997184Stimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 23007184Stimh nvlist_t *zplprops, boolean_t *is_ci) 23017184Stimh { 23027184Stimh boolean_t fuids_ok = B_TRUE; 23037184Stimh uint64_t zplver = ZPL_VERSION; 23047184Stimh objset_t *os = NULL; 23057184Stimh char parentname[MAXNAMELEN]; 23067184Stimh char *cp; 23077184Stimh int error; 23087184Stimh 23097184Stimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 23107184Stimh cp = strrchr(parentname, '/'); 23117184Stimh ASSERT(cp != NULL); 23127184Stimh cp[0] = '\0'; 23137184Stimh 23149396SMatthew.Ahrens@Sun.COM if (zfs_earlier_version(dataset, SPA_VERSION_USERSPACE)) 23159396SMatthew.Ahrens@Sun.COM zplver = ZPL_VERSION_USERSPACE - 1; 23167184Stimh if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 23177184Stimh zplver = ZPL_VERSION_FUID - 1; 23187184Stimh fuids_ok = B_FALSE; 23197184Stimh } 23207184Stimh 23217184Stimh /* 23227184Stimh * Open parent object set so we can inherit zplprop values. 23237184Stimh */ 2324*10298SMatthew.Ahrens@Sun.COM if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0) 23257184Stimh return (error); 23267184Stimh 23277184Stimh error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 23287184Stimh zplprops, is_ci); 2329*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 23307184Stimh return (error); 23317184Stimh } 23327184Stimh 23337184Stimh static int 23347184Stimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 23357184Stimh nvlist_t *zplprops, boolean_t *is_ci) 23367184Stimh { 23377184Stimh boolean_t fuids_ok = B_TRUE; 23387184Stimh uint64_t zplver = ZPL_VERSION; 23397184Stimh int error; 23407184Stimh 23417184Stimh if (spa_vers < SPA_VERSION_FUID) { 23427184Stimh zplver = ZPL_VERSION_FUID - 1; 23437184Stimh fuids_ok = B_FALSE; 23447184Stimh } 23457184Stimh 23467184Stimh error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 23477184Stimh zplprops, is_ci); 23487184Stimh return (error); 2349789Sahrens } 2350789Sahrens 23515367Sahrens /* 23525367Sahrens * inputs: 23535367Sahrens * zc_objset_type type of objset to create (fs vs zvol) 23545367Sahrens * zc_name name of new objset 23555367Sahrens * zc_value name of snapshot to clone from (may be empty) 23565367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 23575367Sahrens * 23585498Stimh * outputs: none 23595367Sahrens */ 2360789Sahrens static int 2361789Sahrens zfs_ioc_create(zfs_cmd_t *zc) 2362789Sahrens { 2363789Sahrens objset_t *clone; 2364789Sahrens int error = 0; 23655331Samw zfs_creat_t zct; 23664543Smarks nvlist_t *nvprops = NULL; 23674543Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2368789Sahrens dmu_objset_type_t type = zc->zc_objset_type; 2369789Sahrens 2370789Sahrens switch (type) { 2371789Sahrens 2372789Sahrens case DMU_OST_ZFS: 2373789Sahrens cbfunc = zfs_create_cb; 2374789Sahrens break; 2375789Sahrens 2376789Sahrens case DMU_OST_ZVOL: 2377789Sahrens cbfunc = zvol_create_cb; 2378789Sahrens break; 2379789Sahrens 2380789Sahrens default: 23812199Sahrens cbfunc = NULL; 23826423Sgw25295 break; 23832199Sahrens } 23845326Sek110237 if (strchr(zc->zc_name, '@') || 23855326Sek110237 strchr(zc->zc_name, '%')) 2386789Sahrens return (EINVAL); 2387789Sahrens 23882676Seschrock if (zc->zc_nvlist_src != NULL && 23895094Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 23909643SEric.Taylor@Sun.COM zc->zc_iflags, &nvprops)) != 0) 23912676Seschrock return (error); 23922676Seschrock 23935498Stimh zct.zct_zplprops = NULL; 23945331Samw zct.zct_props = nvprops; 23955331Samw 23962676Seschrock if (zc->zc_value[0] != '\0') { 2397789Sahrens /* 2398789Sahrens * We're creating a clone of an existing snapshot. 2399789Sahrens */ 24002676Seschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 24012676Seschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 24024543Smarks nvlist_free(nvprops); 2403789Sahrens return (EINVAL); 24042676Seschrock } 2405789Sahrens 2406*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(zc->zc_value, FTAG, &clone); 24072676Seschrock if (error) { 24084543Smarks nvlist_free(nvprops); 2409789Sahrens return (error); 24102676Seschrock } 24116492Stimh 241210272SMatthew.Ahrens@Sun.COM error = dmu_objset_clone(zc->zc_name, dmu_objset_ds(clone), 0); 2413*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(clone, FTAG); 24145331Samw if (error) { 24155331Samw nvlist_free(nvprops); 24165331Samw return (error); 24175331Samw } 2418789Sahrens } else { 24196492Stimh boolean_t is_insensitive = B_FALSE; 24206492Stimh 24212676Seschrock if (cbfunc == NULL) { 24224543Smarks nvlist_free(nvprops); 24232199Sahrens return (EINVAL); 24242676Seschrock } 24252676Seschrock 2426789Sahrens if (type == DMU_OST_ZVOL) { 24272676Seschrock uint64_t volsize, volblocksize; 24282676Seschrock 24294543Smarks if (nvprops == NULL || 24304543Smarks nvlist_lookup_uint64(nvprops, 24312676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 24322676Seschrock &volsize) != 0) { 24334543Smarks nvlist_free(nvprops); 24342676Seschrock return (EINVAL); 24352676Seschrock } 24362676Seschrock 24374543Smarks if ((error = nvlist_lookup_uint64(nvprops, 24382676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 24392676Seschrock &volblocksize)) != 0 && error != ENOENT) { 24404543Smarks nvlist_free(nvprops); 24412676Seschrock return (EINVAL); 24422676Seschrock } 24431133Seschrock 24442676Seschrock if (error != 0) 24452676Seschrock volblocksize = zfs_prop_default_numeric( 24462676Seschrock ZFS_PROP_VOLBLOCKSIZE); 24472676Seschrock 24482676Seschrock if ((error = zvol_check_volblocksize( 24492676Seschrock volblocksize)) != 0 || 24502676Seschrock (error = zvol_check_volsize(volsize, 24512676Seschrock volblocksize)) != 0) { 24524543Smarks nvlist_free(nvprops); 2453789Sahrens return (error); 24542676Seschrock } 24554577Sahrens } else if (type == DMU_OST_ZFS) { 24565331Samw int error; 24575331Samw 24585498Stimh /* 24595331Samw * We have to have normalization and 24605331Samw * case-folding flags correct when we do the 24615331Samw * file system creation, so go figure them out 24625498Stimh * now. 24635331Samw */ 24645498Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 24655498Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 24665498Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 24677184Stimh zct.zct_zplprops, &is_insensitive); 24685331Samw if (error != 0) { 24695331Samw nvlist_free(nvprops); 24705498Stimh nvlist_free(zct.zct_zplprops); 24715331Samw return (error); 24724577Sahrens } 24732676Seschrock } 247410272SMatthew.Ahrens@Sun.COM error = dmu_objset_create(zc->zc_name, type, 24756492Stimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 24765498Stimh nvlist_free(zct.zct_zplprops); 2477789Sahrens } 24782676Seschrock 24792676Seschrock /* 24802676Seschrock * It would be nice to do this atomically. 24812676Seschrock */ 24822676Seschrock if (error == 0) { 24834787Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 248410242Schris.kirby@sun.com (void) dmu_objset_destroy(zc->zc_name, B_FALSE); 24852676Seschrock } 24864543Smarks nvlist_free(nvprops); 2487789Sahrens return (error); 2488789Sahrens } 2489789Sahrens 24905367Sahrens /* 24915367Sahrens * inputs: 24925367Sahrens * zc_name name of filesystem 24935367Sahrens * zc_value short name of snapshot 24945367Sahrens * zc_cookie recursive flag 24959396SMatthew.Ahrens@Sun.COM * zc_nvlist_src[_size] property list 24965367Sahrens * 24975367Sahrens * outputs: none 24985367Sahrens */ 2499789Sahrens static int 25002199Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 25012199Sahrens { 25027265Sahrens nvlist_t *nvprops = NULL; 25037265Sahrens int error; 25047265Sahrens boolean_t recursive = zc->zc_cookie; 25057265Sahrens 25062676Seschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 25072199Sahrens return (EINVAL); 25087265Sahrens 25097265Sahrens if (zc->zc_nvlist_src != NULL && 25107265Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 25119643SEric.Taylor@Sun.COM zc->zc_iflags, &nvprops)) != 0) 25127265Sahrens return (error); 25137265Sahrens 25149355SMatthew.Ahrens@Sun.COM error = zfs_check_userprops(zc->zc_name, nvprops); 25159355SMatthew.Ahrens@Sun.COM if (error) 25169355SMatthew.Ahrens@Sun.COM goto out; 25179355SMatthew.Ahrens@Sun.COM 25189355SMatthew.Ahrens@Sun.COM if (nvprops != NULL && nvlist_next_nvpair(nvprops, NULL) != NULL && 25199355SMatthew.Ahrens@Sun.COM zfs_earlier_version(zc->zc_name, SPA_VERSION_SNAP_PROPS)) { 25209355SMatthew.Ahrens@Sun.COM error = ENOTSUP; 25219355SMatthew.Ahrens@Sun.COM goto out; 25227265Sahrens } 25239355SMatthew.Ahrens@Sun.COM 25249355SMatthew.Ahrens@Sun.COM error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, 25259355SMatthew.Ahrens@Sun.COM nvprops, recursive); 25269355SMatthew.Ahrens@Sun.COM 25279355SMatthew.Ahrens@Sun.COM out: 25287265Sahrens nvlist_free(nvprops); 25297265Sahrens return (error); 25302199Sahrens } 25312199Sahrens 25324007Smmusante int 25332199Sahrens zfs_unmount_snap(char *name, void *arg) 2534789Sahrens { 25352417Sahrens vfs_t *vfsp = NULL; 25362199Sahrens 25376689Smaybee if (arg) { 25386689Smaybee char *snapname = arg; 25396689Smaybee int len = strlen(name) + strlen(snapname) + 2; 25406689Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 25416689Smaybee 25426689Smaybee (void) strcpy(buf, name); 25436689Smaybee (void) strcat(buf, "@"); 25446689Smaybee (void) strcat(buf, snapname); 25456689Smaybee vfsp = zfs_get_vfs(buf); 25466689Smaybee kmem_free(buf, len); 25472417Sahrens } else if (strchr(name, '@')) { 25482199Sahrens vfsp = zfs_get_vfs(name); 25492199Sahrens } 25502199Sahrens 25512199Sahrens if (vfsp) { 25522199Sahrens /* 25532199Sahrens * Always force the unmount for snapshots. 25542199Sahrens */ 25552199Sahrens int flag = MS_FORCE; 2556789Sahrens int err; 2557789Sahrens 25582199Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 25592199Sahrens VFS_RELE(vfsp); 25602199Sahrens return (err); 25612199Sahrens } 25622199Sahrens VFS_RELE(vfsp); 25632199Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 25642199Sahrens return (err); 25652199Sahrens } 25662199Sahrens return (0); 25672199Sahrens } 25682199Sahrens 25695367Sahrens /* 25705367Sahrens * inputs: 257110242Schris.kirby@sun.com * zc_name name of filesystem 257210242Schris.kirby@sun.com * zc_value short name of snapshot 257310242Schris.kirby@sun.com * zc_defer_destroy mark for deferred destroy 25745367Sahrens * 25755367Sahrens * outputs: none 25765367Sahrens */ 25772199Sahrens static int 25782199Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 25792199Sahrens { 25802199Sahrens int err; 2581789Sahrens 25822676Seschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 25832199Sahrens return (EINVAL); 25842199Sahrens err = dmu_objset_find(zc->zc_name, 25852676Seschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 25862199Sahrens if (err) 25872199Sahrens return (err); 258810242Schris.kirby@sun.com return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value, 258910242Schris.kirby@sun.com zc->zc_defer_destroy)); 25902199Sahrens } 25912199Sahrens 25925367Sahrens /* 25935367Sahrens * inputs: 25945367Sahrens * zc_name name of dataset to destroy 25955367Sahrens * zc_objset_type type of objset 259610242Schris.kirby@sun.com * zc_defer_destroy mark for deferred destroy 25975367Sahrens * 25985367Sahrens * outputs: none 25995367Sahrens */ 26002199Sahrens static int 26012199Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 26022199Sahrens { 26032199Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 26042199Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 26052199Sahrens if (err) 26062199Sahrens return (err); 2607789Sahrens } 2608789Sahrens 260910242Schris.kirby@sun.com return (dmu_objset_destroy(zc->zc_name, zc->zc_defer_destroy)); 2610789Sahrens } 2611789Sahrens 26125367Sahrens /* 26135367Sahrens * inputs: 26145446Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 26155367Sahrens * 26165367Sahrens * outputs: none 26175367Sahrens */ 2618789Sahrens static int 2619789Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2620789Sahrens { 262110272SMatthew.Ahrens@Sun.COM dsl_dataset_t *ds, *clone; 26225446Sahrens int error; 262310272SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs; 262410272SMatthew.Ahrens@Sun.COM char *clone_name; 262510272SMatthew.Ahrens@Sun.COM 262610272SMatthew.Ahrens@Sun.COM error = dsl_dataset_hold(zc->zc_name, FTAG, &ds); 262710272SMatthew.Ahrens@Sun.COM if (error) 262810272SMatthew.Ahrens@Sun.COM return (error); 262910272SMatthew.Ahrens@Sun.COM 263010272SMatthew.Ahrens@Sun.COM /* must not be a snapshot */ 263110272SMatthew.Ahrens@Sun.COM if (dsl_dataset_is_snapshot(ds)) { 263210272SMatthew.Ahrens@Sun.COM dsl_dataset_rele(ds, FTAG); 263310272SMatthew.Ahrens@Sun.COM return (EINVAL); 263410272SMatthew.Ahrens@Sun.COM } 263510272SMatthew.Ahrens@Sun.COM 263610272SMatthew.Ahrens@Sun.COM /* must have a most recent snapshot */ 263710272SMatthew.Ahrens@Sun.COM if (ds->ds_phys->ds_prev_snap_txg < TXG_INITIAL) { 263810272SMatthew.Ahrens@Sun.COM dsl_dataset_rele(ds, FTAG); 263910272SMatthew.Ahrens@Sun.COM return (EINVAL); 264010272SMatthew.Ahrens@Sun.COM } 26415446Sahrens 26425446Sahrens /* 264310272SMatthew.Ahrens@Sun.COM * Create clone of most recent snapshot. 26445446Sahrens */ 264510272SMatthew.Ahrens@Sun.COM clone_name = kmem_asprintf("%s/%%rollback", zc->zc_name); 264610272SMatthew.Ahrens@Sun.COM error = dmu_objset_clone(clone_name, ds->ds_prev, DS_FLAG_INCONSISTENT); 26475446Sahrens if (error) 264810272SMatthew.Ahrens@Sun.COM goto out; 264910272SMatthew.Ahrens@Sun.COM 2650*10298SMatthew.Ahrens@Sun.COM error = dsl_dataset_own(clone_name, B_TRUE, FTAG, &clone); 265110272SMatthew.Ahrens@Sun.COM if (error) 265210272SMatthew.Ahrens@Sun.COM goto out; 265310272SMatthew.Ahrens@Sun.COM 265410272SMatthew.Ahrens@Sun.COM /* 265510272SMatthew.Ahrens@Sun.COM * Do clone swap. 265610272SMatthew.Ahrens@Sun.COM */ 26579396SMatthew.Ahrens@Sun.COM if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 2658*10298SMatthew.Ahrens@Sun.COM error = zfs_suspend_fs(zfsvfs); 26596083Sek110237 if (error == 0) { 26606083Sek110237 int resume_err; 26616083Sek110237 266210272SMatthew.Ahrens@Sun.COM if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 266310272SMatthew.Ahrens@Sun.COM error = dsl_dataset_clone_swap(clone, ds, 266410272SMatthew.Ahrens@Sun.COM B_TRUE); 266510272SMatthew.Ahrens@Sun.COM dsl_dataset_disown(ds, FTAG); 266610272SMatthew.Ahrens@Sun.COM ds = NULL; 266710272SMatthew.Ahrens@Sun.COM } else { 266810272SMatthew.Ahrens@Sun.COM error = EBUSY; 266910272SMatthew.Ahrens@Sun.COM } 2670*10298SMatthew.Ahrens@Sun.COM resume_err = zfs_resume_fs(zfsvfs, zc->zc_name); 26716083Sek110237 error = error ? error : resume_err; 26726083Sek110237 } 26735446Sahrens VFS_RELE(zfsvfs->z_vfs); 26745446Sahrens } else { 267510272SMatthew.Ahrens@Sun.COM if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 267610272SMatthew.Ahrens@Sun.COM error = dsl_dataset_clone_swap(clone, ds, B_TRUE); 267710272SMatthew.Ahrens@Sun.COM dsl_dataset_disown(ds, FTAG); 267810272SMatthew.Ahrens@Sun.COM ds = NULL; 267910272SMatthew.Ahrens@Sun.COM } else { 268010272SMatthew.Ahrens@Sun.COM error = EBUSY; 268110272SMatthew.Ahrens@Sun.COM } 26825446Sahrens } 268310272SMatthew.Ahrens@Sun.COM 268410272SMatthew.Ahrens@Sun.COM /* 268510272SMatthew.Ahrens@Sun.COM * Destroy clone (which also closes it). 268610272SMatthew.Ahrens@Sun.COM */ 268710272SMatthew.Ahrens@Sun.COM (void) dsl_dataset_destroy(clone, FTAG, B_FALSE); 268810272SMatthew.Ahrens@Sun.COM 268910272SMatthew.Ahrens@Sun.COM out: 269010272SMatthew.Ahrens@Sun.COM strfree(clone_name); 269110272SMatthew.Ahrens@Sun.COM if (ds) 269210272SMatthew.Ahrens@Sun.COM dsl_dataset_rele(ds, FTAG); 26935446Sahrens return (error); 2694789Sahrens } 2695789Sahrens 26965367Sahrens /* 26975367Sahrens * inputs: 26985367Sahrens * zc_name old name of dataset 26995367Sahrens * zc_value new name of dataset 27005367Sahrens * zc_cookie recursive flag (only valid for snapshots) 27015367Sahrens * 27025367Sahrens * outputs: none 27035367Sahrens */ 2704789Sahrens static int 2705789Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2706789Sahrens { 27074490Svb160487 boolean_t recursive = zc->zc_cookie & 1; 27084007Smmusante 27092676Seschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 27105326Sek110237 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 27115326Sek110237 strchr(zc->zc_value, '%')) 2712789Sahrens return (EINVAL); 2713789Sahrens 27144007Smmusante /* 27154007Smmusante * Unmount snapshot unless we're doing a recursive rename, 27164007Smmusante * in which case the dataset code figures out which snapshots 27174007Smmusante * to unmount. 27184007Smmusante */ 27194007Smmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2720789Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 27212199Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 27222199Sahrens if (err) 27232199Sahrens return (err); 2724789Sahrens } 27254007Smmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2726789Sahrens } 2727789Sahrens 27286689Smaybee static void 27298536SDavid.Pacheco@Sun.COM clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops) 27306689Smaybee { 27316689Smaybee zfs_cmd_t *zc; 27326689Smaybee nvpair_t *prop; 27336689Smaybee 27346689Smaybee if (props == NULL) 27356689Smaybee return; 27366689Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 27376689Smaybee (void) strcpy(zc->zc_name, dataset); 27386689Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 27396689Smaybee prop = nvlist_next_nvpair(props, prop)) { 27408536SDavid.Pacheco@Sun.COM if (newprops != NULL && 27418536SDavid.Pacheco@Sun.COM nvlist_exists(newprops, nvpair_name(prop))) 27428536SDavid.Pacheco@Sun.COM continue; 27436689Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 27446689Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 27456689Smaybee (void) zfs_ioc_inherit_prop(zc); 27466689Smaybee } 27476689Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 27486689Smaybee } 27496689Smaybee 27505367Sahrens /* 27515367Sahrens * inputs: 27525367Sahrens * zc_name name of containing filesystem 27535367Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 27545367Sahrens * zc_value name of snapshot to create 27555367Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 27565367Sahrens * zc_cookie file descriptor to recv from 27575367Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 27585367Sahrens * zc_guid force flag 27595367Sahrens * 27605367Sahrens * outputs: 27615367Sahrens * zc_cookie number of bytes read 27625367Sahrens */ 2763789Sahrens static int 27645367Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2765789Sahrens { 2766789Sahrens file_t *fp; 27675326Sek110237 objset_t *os; 27685367Sahrens dmu_recv_cookie_t drc; 27695326Sek110237 boolean_t force = (boolean_t)zc->zc_guid; 2770789Sahrens int error, fd; 27715367Sahrens offset_t off; 27725367Sahrens nvlist_t *props = NULL; 27736689Smaybee nvlist_t *origprops = NULL; 27745367Sahrens objset_t *origin = NULL; 27755367Sahrens char *tosnap; 27765367Sahrens char tofs[ZFS_MAXNAMELEN]; 2777789Sahrens 27783265Sahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 27795326Sek110237 strchr(zc->zc_value, '@') == NULL || 27805326Sek110237 strchr(zc->zc_value, '%')) 27813265Sahrens return (EINVAL); 27823265Sahrens 27835367Sahrens (void) strcpy(tofs, zc->zc_value); 27845367Sahrens tosnap = strchr(tofs, '@'); 27855367Sahrens *tosnap = '\0'; 27865367Sahrens tosnap++; 27875367Sahrens 27885367Sahrens if (zc->zc_nvlist_src != NULL && 27895367Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 27909643SEric.Taylor@Sun.COM zc->zc_iflags, &props)) != 0) 27915367Sahrens return (error); 27925367Sahrens 2793789Sahrens fd = zc->zc_cookie; 2794789Sahrens fp = getf(fd); 27955367Sahrens if (fp == NULL) { 27965367Sahrens nvlist_free(props); 2797789Sahrens return (EBADF); 27985367Sahrens } 27995326Sek110237 2800*10298SMatthew.Ahrens@Sun.COM if (props && dmu_objset_hold(tofs, FTAG, &os) == 0) { 28016689Smaybee /* 28026689Smaybee * If new properties are supplied, they are to completely 28036689Smaybee * replace the existing ones, so stash away the existing ones. 28046689Smaybee */ 2805*10298SMatthew.Ahrens@Sun.COM (void) dsl_prop_get_all(os, &origprops, B_TRUE); 2806*10298SMatthew.Ahrens@Sun.COM 2807*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 28085326Sek110237 } 28095326Sek110237 28105367Sahrens if (zc->zc_string[0]) { 2811*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(zc->zc_string, FTAG, &origin); 28126689Smaybee if (error) 28136689Smaybee goto out; 28145367Sahrens } 28155367Sahrens 28165367Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 281710204SMatthew.Ahrens@Sun.COM force, origin, &drc); 28185367Sahrens if (origin) 2819*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(origin, FTAG); 28206689Smaybee if (error) 28216689Smaybee goto out; 28225326Sek110237 28235326Sek110237 /* 28246689Smaybee * Reset properties. We do this before we receive the stream 28256689Smaybee * so that the properties are applied to the new data. 28265326Sek110237 */ 28275367Sahrens if (props) { 28288536SDavid.Pacheco@Sun.COM clear_props(tofs, origprops, props); 28296689Smaybee /* 28306689Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 28316689Smaybee */ 28326689Smaybee (void) zfs_set_prop_nvlist(tofs, props); 28335367Sahrens } 28345367Sahrens 28355367Sahrens off = fp->f_offset; 28365367Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 28375367Sahrens 283810204SMatthew.Ahrens@Sun.COM if (error == 0) { 283910204SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs = NULL; 284010204SMatthew.Ahrens@Sun.COM 284110204SMatthew.Ahrens@Sun.COM if (getzfsvfs(tofs, &zfsvfs) == 0) { 284210204SMatthew.Ahrens@Sun.COM /* online recv */ 284310204SMatthew.Ahrens@Sun.COM int end_err; 2844*10298SMatthew.Ahrens@Sun.COM 2845*10298SMatthew.Ahrens@Sun.COM error = zfs_suspend_fs(zfsvfs); 284610204SMatthew.Ahrens@Sun.COM /* 284710204SMatthew.Ahrens@Sun.COM * If the suspend fails, then the recv_end will 284810204SMatthew.Ahrens@Sun.COM * likely also fail, and clean up after itself. 284910204SMatthew.Ahrens@Sun.COM */ 285010204SMatthew.Ahrens@Sun.COM end_err = dmu_recv_end(&drc); 285110204SMatthew.Ahrens@Sun.COM if (error == 0) { 285210204SMatthew.Ahrens@Sun.COM int resume_err = 2853*10298SMatthew.Ahrens@Sun.COM zfs_resume_fs(zfsvfs, tofs); 285410204SMatthew.Ahrens@Sun.COM error = error ? error : resume_err; 285510204SMatthew.Ahrens@Sun.COM } 285610204SMatthew.Ahrens@Sun.COM error = error ? error : end_err; 285710204SMatthew.Ahrens@Sun.COM VFS_RELE(zfsvfs->z_vfs); 285810204SMatthew.Ahrens@Sun.COM } else { 28596689Smaybee error = dmu_recv_end(&drc); 28605367Sahrens } 28616083Sek110237 } 28625367Sahrens 28635367Sahrens zc->zc_cookie = off - fp->f_offset; 28645367Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 28655367Sahrens fp->f_offset = off; 28662885Sahrens 28676689Smaybee /* 28686689Smaybee * On error, restore the original props. 28696689Smaybee */ 28706689Smaybee if (error && props) { 28718536SDavid.Pacheco@Sun.COM clear_props(tofs, props, NULL); 28726689Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 28736689Smaybee } 28746689Smaybee out: 28756689Smaybee nvlist_free(props); 28766689Smaybee nvlist_free(origprops); 2877789Sahrens releasef(fd); 2878789Sahrens return (error); 2879789Sahrens } 2880789Sahrens 28815367Sahrens /* 28825367Sahrens * inputs: 28835367Sahrens * zc_name name of snapshot to send 28845367Sahrens * zc_value short name of incremental fromsnap (may be empty) 28855367Sahrens * zc_cookie file descriptor to send stream to 28865367Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 28875367Sahrens * 28885367Sahrens * outputs: none 28895367Sahrens */ 2890789Sahrens static int 28915367Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2892789Sahrens { 2893789Sahrens objset_t *fromsnap = NULL; 2894789Sahrens objset_t *tosnap; 2895789Sahrens file_t *fp; 2896789Sahrens int error; 28975367Sahrens offset_t off; 2898789Sahrens 2899*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(zc->zc_name, FTAG, &tosnap); 2900789Sahrens if (error) 2901789Sahrens return (error); 2902789Sahrens 29032676Seschrock if (zc->zc_value[0] != '\0') { 29048012SEric.Taylor@Sun.COM char *buf; 29052885Sahrens char *cp; 29062885Sahrens 29078012SEric.Taylor@Sun.COM buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 29088012SEric.Taylor@Sun.COM (void) strncpy(buf, zc->zc_name, MAXPATHLEN); 29092885Sahrens cp = strchr(buf, '@'); 29102885Sahrens if (cp) 29112885Sahrens *(cp+1) = 0; 29128012SEric.Taylor@Sun.COM (void) strncat(buf, zc->zc_value, MAXPATHLEN); 2913*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(buf, FTAG, &fromsnap); 29148012SEric.Taylor@Sun.COM kmem_free(buf, MAXPATHLEN); 2915789Sahrens if (error) { 2916*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(tosnap, FTAG); 2917789Sahrens return (error); 2918789Sahrens } 2919789Sahrens } 2920789Sahrens 2921789Sahrens fp = getf(zc->zc_cookie); 2922789Sahrens if (fp == NULL) { 2923*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(tosnap, FTAG); 2924789Sahrens if (fromsnap) 2925*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(fromsnap, FTAG); 2926789Sahrens return (EBADF); 2927789Sahrens } 2928789Sahrens 29295367Sahrens off = fp->f_offset; 29305367Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 29315367Sahrens 29325367Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 29335367Sahrens fp->f_offset = off; 2934789Sahrens releasef(zc->zc_cookie); 2935789Sahrens if (fromsnap) 2936*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(fromsnap, FTAG); 2937*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(tosnap, FTAG); 2938789Sahrens return (error); 2939789Sahrens } 2940789Sahrens 29411544Seschrock static int 29421544Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 29431544Seschrock { 29441544Seschrock int id, error; 29451544Seschrock 29461544Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 29471544Seschrock &zc->zc_inject_record); 29481544Seschrock 29491544Seschrock if (error == 0) 29501544Seschrock zc->zc_guid = (uint64_t)id; 29511544Seschrock 29521544Seschrock return (error); 29531544Seschrock } 29541544Seschrock 29551544Seschrock static int 29561544Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 29571544Seschrock { 29581544Seschrock return (zio_clear_fault((int)zc->zc_guid)); 29591544Seschrock } 29601544Seschrock 29611544Seschrock static int 29621544Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 29631544Seschrock { 29641544Seschrock int id = (int)zc->zc_guid; 29651544Seschrock int error; 29661544Seschrock 29671544Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 29681544Seschrock &zc->zc_inject_record); 29691544Seschrock 29701544Seschrock zc->zc_guid = id; 29711544Seschrock 29721544Seschrock return (error); 29731544Seschrock } 29741544Seschrock 29751544Seschrock static int 29761544Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 29771544Seschrock { 29781544Seschrock spa_t *spa; 29791544Seschrock int error; 29802676Seschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 29811544Seschrock 29821544Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 29831544Seschrock return (error); 29841544Seschrock 29852676Seschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 29861544Seschrock &count); 29871544Seschrock if (error == 0) 29882676Seschrock zc->zc_nvlist_dst_size = count; 29891544Seschrock else 29902676Seschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 29911544Seschrock 29921544Seschrock spa_close(spa, FTAG); 29931544Seschrock 29941544Seschrock return (error); 29951544Seschrock } 29961544Seschrock 29971544Seschrock static int 29981544Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 29991544Seschrock { 30001544Seschrock spa_t *spa; 30011544Seschrock vdev_t *vd; 30021544Seschrock int error; 30031544Seschrock 30047294Sperrin /* 30057294Sperrin * On zpool clear we also fix up missing slogs 30067294Sperrin */ 30077294Sperrin mutex_enter(&spa_namespace_lock); 30087294Sperrin spa = spa_lookup(zc->zc_name); 30097294Sperrin if (spa == NULL) { 30107294Sperrin mutex_exit(&spa_namespace_lock); 30117294Sperrin return (EIO); 30127294Sperrin } 30137294Sperrin if (spa->spa_log_state == SPA_LOG_MISSING) { 30147294Sperrin /* we need to let spa_open/spa_load clear the chains */ 30157294Sperrin spa->spa_log_state = SPA_LOG_CLEAR; 30167294Sperrin } 30177294Sperrin mutex_exit(&spa_namespace_lock); 30187294Sperrin 30191544Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 30201544Seschrock return (error); 30211544Seschrock 30227754SJeff.Bonwick@Sun.COM spa_vdev_state_enter(spa); 30231544Seschrock 30242676Seschrock if (zc->zc_guid == 0) { 30251544Seschrock vd = NULL; 30266643Seschrock } else { 30276643Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 30285450Sbrendan if (vd == NULL) { 30297754SJeff.Bonwick@Sun.COM (void) spa_vdev_state_exit(spa, NULL, ENODEV); 30305450Sbrendan spa_close(spa, FTAG); 30315450Sbrendan return (ENODEV); 30325450Sbrendan } 30331544Seschrock } 30341544Seschrock 30357754SJeff.Bonwick@Sun.COM vdev_clear(spa, vd); 30367754SJeff.Bonwick@Sun.COM 30377754SJeff.Bonwick@Sun.COM (void) spa_vdev_state_exit(spa, NULL, 0); 30387754SJeff.Bonwick@Sun.COM 30397754SJeff.Bonwick@Sun.COM /* 30407754SJeff.Bonwick@Sun.COM * Resume any suspended I/Os. 30417754SJeff.Bonwick@Sun.COM */ 30429234SGeorge.Wilson@Sun.COM if (zio_resume(spa) != 0) 30439234SGeorge.Wilson@Sun.COM error = EIO; 30441544Seschrock 30451544Seschrock spa_close(spa, FTAG); 30461544Seschrock 30479234SGeorge.Wilson@Sun.COM return (error); 30481544Seschrock } 30491544Seschrock 30505367Sahrens /* 30515367Sahrens * inputs: 30525367Sahrens * zc_name name of filesystem 30535367Sahrens * zc_value name of origin snapshot 30545367Sahrens * 30555367Sahrens * outputs: none 30565367Sahrens */ 30571544Seschrock static int 30582082Seschrock zfs_ioc_promote(zfs_cmd_t *zc) 30592082Seschrock { 30602417Sahrens char *cp; 30612417Sahrens 30622417Sahrens /* 30632417Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 30642417Sahrens * it's easier. 30652417Sahrens */ 30662676Seschrock cp = strchr(zc->zc_value, '@'); 30672417Sahrens if (cp) 30682417Sahrens *cp = '\0'; 30692676Seschrock (void) dmu_objset_find(zc->zc_value, 30702417Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 30712082Seschrock return (dsl_dataset_promote(zc->zc_name)); 30722082Seschrock } 30732082Seschrock 30744543Smarks /* 30759396SMatthew.Ahrens@Sun.COM * Retrieve a single {user|group}{used|quota}@... property. 30769396SMatthew.Ahrens@Sun.COM * 30779396SMatthew.Ahrens@Sun.COM * inputs: 30789396SMatthew.Ahrens@Sun.COM * zc_name name of filesystem 30799396SMatthew.Ahrens@Sun.COM * zc_objset_type zfs_userquota_prop_t 30809396SMatthew.Ahrens@Sun.COM * zc_value domain name (eg. "S-1-234-567-89") 30819396SMatthew.Ahrens@Sun.COM * zc_guid RID/UID/GID 30829396SMatthew.Ahrens@Sun.COM * 30839396SMatthew.Ahrens@Sun.COM * outputs: 30849396SMatthew.Ahrens@Sun.COM * zc_cookie property value 30859396SMatthew.Ahrens@Sun.COM */ 30869396SMatthew.Ahrens@Sun.COM static int 30879396SMatthew.Ahrens@Sun.COM zfs_ioc_userspace_one(zfs_cmd_t *zc) 30889396SMatthew.Ahrens@Sun.COM { 30899396SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs; 30909396SMatthew.Ahrens@Sun.COM int error; 30919396SMatthew.Ahrens@Sun.COM 30929396SMatthew.Ahrens@Sun.COM if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 30939396SMatthew.Ahrens@Sun.COM return (EINVAL); 30949396SMatthew.Ahrens@Sun.COM 3095*10298SMatthew.Ahrens@Sun.COM error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs); 30969396SMatthew.Ahrens@Sun.COM if (error) 30979396SMatthew.Ahrens@Sun.COM return (error); 30989396SMatthew.Ahrens@Sun.COM 30999396SMatthew.Ahrens@Sun.COM error = zfs_userspace_one(zfsvfs, 31009396SMatthew.Ahrens@Sun.COM zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 31019396SMatthew.Ahrens@Sun.COM zfsvfs_rele(zfsvfs, FTAG); 31029396SMatthew.Ahrens@Sun.COM 31039396SMatthew.Ahrens@Sun.COM return (error); 31049396SMatthew.Ahrens@Sun.COM } 31059396SMatthew.Ahrens@Sun.COM 31069396SMatthew.Ahrens@Sun.COM /* 31079396SMatthew.Ahrens@Sun.COM * inputs: 31089396SMatthew.Ahrens@Sun.COM * zc_name name of filesystem 31099396SMatthew.Ahrens@Sun.COM * zc_cookie zap cursor 31109396SMatthew.Ahrens@Sun.COM * zc_objset_type zfs_userquota_prop_t 31119396SMatthew.Ahrens@Sun.COM * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 31129396SMatthew.Ahrens@Sun.COM * 31139396SMatthew.Ahrens@Sun.COM * outputs: 31149396SMatthew.Ahrens@Sun.COM * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 31159396SMatthew.Ahrens@Sun.COM * zc_cookie zap cursor 31169396SMatthew.Ahrens@Sun.COM */ 31179396SMatthew.Ahrens@Sun.COM static int 31189396SMatthew.Ahrens@Sun.COM zfs_ioc_userspace_many(zfs_cmd_t *zc) 31199396SMatthew.Ahrens@Sun.COM { 31209396SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs; 31219396SMatthew.Ahrens@Sun.COM int error; 31229396SMatthew.Ahrens@Sun.COM 3123*10298SMatthew.Ahrens@Sun.COM error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs); 31249396SMatthew.Ahrens@Sun.COM if (error) 31259396SMatthew.Ahrens@Sun.COM return (error); 31269396SMatthew.Ahrens@Sun.COM 31279396SMatthew.Ahrens@Sun.COM int bufsize = zc->zc_nvlist_dst_size; 31289396SMatthew.Ahrens@Sun.COM void *buf = kmem_alloc(bufsize, KM_SLEEP); 31299396SMatthew.Ahrens@Sun.COM 31309396SMatthew.Ahrens@Sun.COM error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 31319396SMatthew.Ahrens@Sun.COM buf, &zc->zc_nvlist_dst_size); 31329396SMatthew.Ahrens@Sun.COM 31339396SMatthew.Ahrens@Sun.COM if (error == 0) { 31349396SMatthew.Ahrens@Sun.COM error = xcopyout(buf, 31359396SMatthew.Ahrens@Sun.COM (void *)(uintptr_t)zc->zc_nvlist_dst, 31369396SMatthew.Ahrens@Sun.COM zc->zc_nvlist_dst_size); 31379396SMatthew.Ahrens@Sun.COM } 31389396SMatthew.Ahrens@Sun.COM kmem_free(buf, bufsize); 31399396SMatthew.Ahrens@Sun.COM zfsvfs_rele(zfsvfs, FTAG); 31409396SMatthew.Ahrens@Sun.COM 31419396SMatthew.Ahrens@Sun.COM return (error); 31429396SMatthew.Ahrens@Sun.COM } 31439396SMatthew.Ahrens@Sun.COM 31449396SMatthew.Ahrens@Sun.COM /* 31459396SMatthew.Ahrens@Sun.COM * inputs: 31469396SMatthew.Ahrens@Sun.COM * zc_name name of filesystem 31479396SMatthew.Ahrens@Sun.COM * 31489396SMatthew.Ahrens@Sun.COM * outputs: 31499396SMatthew.Ahrens@Sun.COM * none 31509396SMatthew.Ahrens@Sun.COM */ 31519396SMatthew.Ahrens@Sun.COM static int 31529396SMatthew.Ahrens@Sun.COM zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 31539396SMatthew.Ahrens@Sun.COM { 31549396SMatthew.Ahrens@Sun.COM objset_t *os; 31559396SMatthew.Ahrens@Sun.COM int error; 31569396SMatthew.Ahrens@Sun.COM zfsvfs_t *zfsvfs; 31579396SMatthew.Ahrens@Sun.COM 31589396SMatthew.Ahrens@Sun.COM if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 3159*10298SMatthew.Ahrens@Sun.COM if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { 31609396SMatthew.Ahrens@Sun.COM /* 31619396SMatthew.Ahrens@Sun.COM * If userused is not enabled, it may be because the 31629396SMatthew.Ahrens@Sun.COM * objset needs to be closed & reopened (to grow the 31639396SMatthew.Ahrens@Sun.COM * objset_phys_t). Suspend/resume the fs will do that. 31649396SMatthew.Ahrens@Sun.COM */ 3165*10298SMatthew.Ahrens@Sun.COM error = zfs_suspend_fs(zfsvfs); 3166*10298SMatthew.Ahrens@Sun.COM if (error == 0) 3167*10298SMatthew.Ahrens@Sun.COM error = zfs_resume_fs(zfsvfs, zc->zc_name); 31689396SMatthew.Ahrens@Sun.COM } 31699396SMatthew.Ahrens@Sun.COM if (error == 0) 31709396SMatthew.Ahrens@Sun.COM error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 31719396SMatthew.Ahrens@Sun.COM VFS_RELE(zfsvfs->z_vfs); 31729396SMatthew.Ahrens@Sun.COM } else { 3173*10298SMatthew.Ahrens@Sun.COM /* XXX kind of reading contents without owning */ 3174*10298SMatthew.Ahrens@Sun.COM error = dmu_objset_hold(zc->zc_name, FTAG, &os); 31759396SMatthew.Ahrens@Sun.COM if (error) 31769396SMatthew.Ahrens@Sun.COM return (error); 31779396SMatthew.Ahrens@Sun.COM 31789396SMatthew.Ahrens@Sun.COM error = dmu_objset_userspace_upgrade(os); 3179*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(os, FTAG); 31809396SMatthew.Ahrens@Sun.COM } 31819396SMatthew.Ahrens@Sun.COM 31829396SMatthew.Ahrens@Sun.COM return (error); 31839396SMatthew.Ahrens@Sun.COM } 31849396SMatthew.Ahrens@Sun.COM 31859396SMatthew.Ahrens@Sun.COM /* 31864543Smarks * We don't want to have a hard dependency 31874543Smarks * against some special symbols in sharefs 31885331Samw * nfs, and smbsrv. Determine them if needed when 31894543Smarks * the first file system is shared. 31905331Samw * Neither sharefs, nfs or smbsrv are unloadable modules. 31914543Smarks */ 31925331Samw int (*znfsexport_fs)(void *arg); 31934543Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 31945331Samw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 31955331Samw 31965331Samw int zfs_nfsshare_inited; 31975331Samw int zfs_smbshare_inited; 31985331Samw 31994543Smarks ddi_modhandle_t nfs_mod; 32004543Smarks ddi_modhandle_t sharefs_mod; 32015331Samw ddi_modhandle_t smbsrv_mod; 32024543Smarks kmutex_t zfs_share_lock; 32034543Smarks 32044543Smarks static int 32055331Samw zfs_init_sharefs() 32065331Samw { 32075331Samw int error; 32085331Samw 32095331Samw ASSERT(MUTEX_HELD(&zfs_share_lock)); 32105331Samw /* Both NFS and SMB shares also require sharetab support. */ 32115331Samw if (sharefs_mod == NULL && ((sharefs_mod = 32125331Samw ddi_modopen("fs/sharefs", 32135331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 32145331Samw return (ENOSYS); 32155331Samw } 32165331Samw if (zshare_fs == NULL && ((zshare_fs = 32175331Samw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 32185331Samw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 32195331Samw return (ENOSYS); 32205331Samw } 32215331Samw return (0); 32225331Samw } 32235331Samw 32245331Samw static int 32254543Smarks zfs_ioc_share(zfs_cmd_t *zc) 32264543Smarks { 32274543Smarks int error; 32284543Smarks int opcode; 32294543Smarks 32305331Samw switch (zc->zc_share.z_sharetype) { 32315331Samw case ZFS_SHARE_NFS: 32325331Samw case ZFS_UNSHARE_NFS: 32335331Samw if (zfs_nfsshare_inited == 0) { 32345331Samw mutex_enter(&zfs_share_lock); 32355331Samw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 32365331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 32375331Samw mutex_exit(&zfs_share_lock); 32385331Samw return (ENOSYS); 32395331Samw } 32405331Samw if (znfsexport_fs == NULL && 32415331Samw ((znfsexport_fs = (int (*)(void *)) 32425331Samw ddi_modsym(nfs_mod, 32435331Samw "nfs_export", &error)) == NULL)) { 32445331Samw mutex_exit(&zfs_share_lock); 32455331Samw return (ENOSYS); 32465331Samw } 32475331Samw error = zfs_init_sharefs(); 32485331Samw if (error) { 32495331Samw mutex_exit(&zfs_share_lock); 32505331Samw return (ENOSYS); 32515331Samw } 32525331Samw zfs_nfsshare_inited = 1; 32534543Smarks mutex_exit(&zfs_share_lock); 32544543Smarks } 32555331Samw break; 32565331Samw case ZFS_SHARE_SMB: 32575331Samw case ZFS_UNSHARE_SMB: 32585331Samw if (zfs_smbshare_inited == 0) { 32595331Samw mutex_enter(&zfs_share_lock); 32605331Samw if (smbsrv_mod == NULL && ((smbsrv_mod = 32615331Samw ddi_modopen("drv/smbsrv", 32625331Samw KRTLD_MODE_FIRST, &error)) == NULL)) { 32635331Samw mutex_exit(&zfs_share_lock); 32645331Samw return (ENOSYS); 32655331Samw } 32665331Samw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 32675331Samw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 32686139Sjb150015 "smb_server_share", &error)) == NULL)) { 32695331Samw mutex_exit(&zfs_share_lock); 32705331Samw return (ENOSYS); 32715331Samw } 32725331Samw error = zfs_init_sharefs(); 32735331Samw if (error) { 32745331Samw mutex_exit(&zfs_share_lock); 32755331Samw return (ENOSYS); 32765331Samw } 32775331Samw zfs_smbshare_inited = 1; 32784543Smarks mutex_exit(&zfs_share_lock); 32794543Smarks } 32805331Samw break; 32815331Samw default: 32825331Samw return (EINVAL); 32834543Smarks } 32844543Smarks 32855331Samw switch (zc->zc_share.z_sharetype) { 32865331Samw case ZFS_SHARE_NFS: 32875331Samw case ZFS_UNSHARE_NFS: 32885331Samw if (error = 32895331Samw znfsexport_fs((void *) 32905331Samw (uintptr_t)zc->zc_share.z_exportdata)) 32915331Samw return (error); 32925331Samw break; 32935331Samw case ZFS_SHARE_SMB: 32945331Samw case ZFS_UNSHARE_SMB: 32955331Samw if (error = zsmbexport_fs((void *) 32965331Samw (uintptr_t)zc->zc_share.z_exportdata, 32975331Samw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 32988845Samw@Sun.COM B_TRUE: B_FALSE)) { 32995331Samw return (error); 33005331Samw } 33015331Samw break; 33025331Samw } 33035331Samw 33045331Samw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 33055331Samw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 33064543Smarks SHAREFS_ADD : SHAREFS_REMOVE; 33074543Smarks 33085331Samw /* 33095331Samw * Add or remove share from sharetab 33105331Samw */ 33114543Smarks error = zshare_fs(opcode, 33124543Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 33134543Smarks zc->zc_share.z_sharemax); 33144543Smarks 33154543Smarks return (error); 33164543Smarks 33174543Smarks } 33184543Smarks 33198845Samw@Sun.COM ace_t full_access[] = { 33208845Samw@Sun.COM {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 33218845Samw@Sun.COM }; 33228845Samw@Sun.COM 33238845Samw@Sun.COM /* 33248845Samw@Sun.COM * Remove all ACL files in shares dir 33258845Samw@Sun.COM */ 33268845Samw@Sun.COM static int 33278845Samw@Sun.COM zfs_smb_acl_purge(znode_t *dzp) 33288845Samw@Sun.COM { 33298845Samw@Sun.COM zap_cursor_t zc; 33308845Samw@Sun.COM zap_attribute_t zap; 33318845Samw@Sun.COM zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 33328845Samw@Sun.COM int error; 33338845Samw@Sun.COM 33348845Samw@Sun.COM for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 33358845Samw@Sun.COM (error = zap_cursor_retrieve(&zc, &zap)) == 0; 33368845Samw@Sun.COM zap_cursor_advance(&zc)) { 33378845Samw@Sun.COM if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 33388845Samw@Sun.COM NULL, 0)) != 0) 33398845Samw@Sun.COM break; 33408845Samw@Sun.COM } 33418845Samw@Sun.COM zap_cursor_fini(&zc); 33428845Samw@Sun.COM return (error); 33438845Samw@Sun.COM } 33448845Samw@Sun.COM 33458845Samw@Sun.COM static int 33468845Samw@Sun.COM zfs_ioc_smb_acl(zfs_cmd_t *zc) 33478845Samw@Sun.COM { 33488845Samw@Sun.COM vnode_t *vp; 33498845Samw@Sun.COM znode_t *dzp; 33508845Samw@Sun.COM vnode_t *resourcevp = NULL; 33518845Samw@Sun.COM znode_t *sharedir; 33528845Samw@Sun.COM zfsvfs_t *zfsvfs; 33538845Samw@Sun.COM nvlist_t *nvlist; 33548845Samw@Sun.COM char *src, *target; 33558845Samw@Sun.COM vattr_t vattr; 33568845Samw@Sun.COM vsecattr_t vsec; 33578845Samw@Sun.COM int error = 0; 33588845Samw@Sun.COM 33598845Samw@Sun.COM if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 33608845Samw@Sun.COM NO_FOLLOW, NULL, &vp)) != 0) 33618845Samw@Sun.COM return (error); 33628845Samw@Sun.COM 33638845Samw@Sun.COM /* Now make sure mntpnt and dataset are ZFS */ 33648845Samw@Sun.COM 33658845Samw@Sun.COM if (vp->v_vfsp->vfs_fstype != zfsfstype || 33668845Samw@Sun.COM (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 33678845Samw@Sun.COM zc->zc_name) != 0)) { 33688845Samw@Sun.COM VN_RELE(vp); 33698845Samw@Sun.COM return (EINVAL); 33708845Samw@Sun.COM } 33718845Samw@Sun.COM 33728845Samw@Sun.COM dzp = VTOZ(vp); 33738845Samw@Sun.COM zfsvfs = dzp->z_zfsvfs; 33748845Samw@Sun.COM ZFS_ENTER(zfsvfs); 33758845Samw@Sun.COM 33769030SMark.Shellenbaum@Sun.COM /* 33779030SMark.Shellenbaum@Sun.COM * Create share dir if its missing. 33789030SMark.Shellenbaum@Sun.COM */ 33799030SMark.Shellenbaum@Sun.COM mutex_enter(&zfsvfs->z_lock); 33809030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 33819030SMark.Shellenbaum@Sun.COM dmu_tx_t *tx; 33829030SMark.Shellenbaum@Sun.COM 33839030SMark.Shellenbaum@Sun.COM tx = dmu_tx_create(zfsvfs->z_os); 33849030SMark.Shellenbaum@Sun.COM dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 33859030SMark.Shellenbaum@Sun.COM ZFS_SHARES_DIR); 33869030SMark.Shellenbaum@Sun.COM dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 33879030SMark.Shellenbaum@Sun.COM error = dmu_tx_assign(tx, TXG_WAIT); 33889030SMark.Shellenbaum@Sun.COM if (error) { 33899030SMark.Shellenbaum@Sun.COM dmu_tx_abort(tx); 33909030SMark.Shellenbaum@Sun.COM } else { 33919030SMark.Shellenbaum@Sun.COM error = zfs_create_share_dir(zfsvfs, tx); 33929030SMark.Shellenbaum@Sun.COM dmu_tx_commit(tx); 33939030SMark.Shellenbaum@Sun.COM } 33949030SMark.Shellenbaum@Sun.COM if (error) { 33959030SMark.Shellenbaum@Sun.COM mutex_exit(&zfsvfs->z_lock); 33969030SMark.Shellenbaum@Sun.COM VN_RELE(vp); 33979030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 33989030SMark.Shellenbaum@Sun.COM return (error); 33999030SMark.Shellenbaum@Sun.COM } 34009030SMark.Shellenbaum@Sun.COM } 34019030SMark.Shellenbaum@Sun.COM mutex_exit(&zfsvfs->z_lock); 34029030SMark.Shellenbaum@Sun.COM 34039030SMark.Shellenbaum@Sun.COM ASSERT(zfsvfs->z_shares_dir); 34048845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 34059030SMark.Shellenbaum@Sun.COM VN_RELE(vp); 34068845Samw@Sun.COM ZFS_EXIT(zfsvfs); 34078845Samw@Sun.COM return (error); 34088845Samw@Sun.COM } 34098845Samw@Sun.COM 34108845Samw@Sun.COM switch (zc->zc_cookie) { 34118845Samw@Sun.COM case ZFS_SMB_ACL_ADD: 34128845Samw@Sun.COM vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 34138845Samw@Sun.COM vattr.va_type = VREG; 34148845Samw@Sun.COM vattr.va_mode = S_IFREG|0777; 34158845Samw@Sun.COM vattr.va_uid = 0; 34168845Samw@Sun.COM vattr.va_gid = 0; 34178845Samw@Sun.COM 34188845Samw@Sun.COM vsec.vsa_mask = VSA_ACE; 34198845Samw@Sun.COM vsec.vsa_aclentp = &full_access; 34208845Samw@Sun.COM vsec.vsa_aclentsz = sizeof (full_access); 34218845Samw@Sun.COM vsec.vsa_aclcnt = 1; 34228845Samw@Sun.COM 34238845Samw@Sun.COM error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 34248845Samw@Sun.COM &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 34258845Samw@Sun.COM if (resourcevp) 34268845Samw@Sun.COM VN_RELE(resourcevp); 34278845Samw@Sun.COM break; 34288845Samw@Sun.COM 34298845Samw@Sun.COM case ZFS_SMB_ACL_REMOVE: 34308845Samw@Sun.COM error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 34318845Samw@Sun.COM NULL, 0); 34328845Samw@Sun.COM break; 34338845Samw@Sun.COM 34348845Samw@Sun.COM case ZFS_SMB_ACL_RENAME: 34358845Samw@Sun.COM if ((error = get_nvlist(zc->zc_nvlist_src, 34369643SEric.Taylor@Sun.COM zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { 34378845Samw@Sun.COM VN_RELE(vp); 34388845Samw@Sun.COM ZFS_EXIT(zfsvfs); 34398845Samw@Sun.COM return (error); 34408845Samw@Sun.COM } 34418845Samw@Sun.COM if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 34428845Samw@Sun.COM nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 34438845Samw@Sun.COM &target)) { 34448845Samw@Sun.COM VN_RELE(vp); 34459179SMark.Shellenbaum@Sun.COM VN_RELE(ZTOV(sharedir)); 34468845Samw@Sun.COM ZFS_EXIT(zfsvfs); 34478845Samw@Sun.COM return (error); 34488845Samw@Sun.COM } 34498845Samw@Sun.COM error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 34508845Samw@Sun.COM kcred, NULL, 0); 34518845Samw@Sun.COM nvlist_free(nvlist); 34528845Samw@Sun.COM break; 34538845Samw@Sun.COM 34548845Samw@Sun.COM case ZFS_SMB_ACL_PURGE: 34558845Samw@Sun.COM error = zfs_smb_acl_purge(sharedir); 34568845Samw@Sun.COM break; 34578845Samw@Sun.COM 34588845Samw@Sun.COM default: 34598845Samw@Sun.COM error = EINVAL; 34608845Samw@Sun.COM break; 34618845Samw@Sun.COM } 34628845Samw@Sun.COM 34638845Samw@Sun.COM VN_RELE(vp); 34648845Samw@Sun.COM VN_RELE(ZTOV(sharedir)); 34658845Samw@Sun.COM 34668845Samw@Sun.COM ZFS_EXIT(zfsvfs); 34678845Samw@Sun.COM 34688845Samw@Sun.COM return (error); 34698845Samw@Sun.COM } 34708845Samw@Sun.COM 34714543Smarks /* 347210242Schris.kirby@sun.com * inputs: 347310242Schris.kirby@sun.com * zc_name name of filesystem 347410242Schris.kirby@sun.com * zc_value short name of snap 347510242Schris.kirby@sun.com * zc_string user-supplied tag for this reference 347610242Schris.kirby@sun.com * zc_cookie recursive flag 347710242Schris.kirby@sun.com * 347810242Schris.kirby@sun.com * outputs: none 347910242Schris.kirby@sun.com */ 348010242Schris.kirby@sun.com static int 348110242Schris.kirby@sun.com zfs_ioc_hold(zfs_cmd_t *zc) 348210242Schris.kirby@sun.com { 348310242Schris.kirby@sun.com boolean_t recursive = zc->zc_cookie; 348410242Schris.kirby@sun.com 348510242Schris.kirby@sun.com if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 348610242Schris.kirby@sun.com return (EINVAL); 348710242Schris.kirby@sun.com 348810242Schris.kirby@sun.com return (dsl_dataset_user_hold(zc->zc_name, zc->zc_value, 348910242Schris.kirby@sun.com zc->zc_string, recursive)); 349010242Schris.kirby@sun.com } 349110242Schris.kirby@sun.com 349210242Schris.kirby@sun.com /* 349310242Schris.kirby@sun.com * inputs: 349410242Schris.kirby@sun.com * zc_name name of dataset from which we're releasing a user reference 349510242Schris.kirby@sun.com * zc_value short name of snap 349610242Schris.kirby@sun.com * zc_string user-supplied tag for this reference 349710242Schris.kirby@sun.com * zc_cookie recursive flag 349810242Schris.kirby@sun.com * 349910242Schris.kirby@sun.com * outputs: none 350010242Schris.kirby@sun.com */ 350110242Schris.kirby@sun.com static int 350210242Schris.kirby@sun.com zfs_ioc_release(zfs_cmd_t *zc) 350310242Schris.kirby@sun.com { 350410242Schris.kirby@sun.com boolean_t recursive = zc->zc_cookie; 350510242Schris.kirby@sun.com 350610242Schris.kirby@sun.com if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 350710242Schris.kirby@sun.com return (EINVAL); 350810242Schris.kirby@sun.com 350910242Schris.kirby@sun.com return (dsl_dataset_user_release(zc->zc_name, zc->zc_value, 351010242Schris.kirby@sun.com zc->zc_string, recursive)); 351110242Schris.kirby@sun.com } 351210242Schris.kirby@sun.com 351310242Schris.kirby@sun.com /* 351410242Schris.kirby@sun.com * inputs: 351510242Schris.kirby@sun.com * zc_name name of filesystem 351610242Schris.kirby@sun.com * 351710242Schris.kirby@sun.com * outputs: 351810242Schris.kirby@sun.com * zc_nvlist_src{_size} nvlist of snapshot holds 351910242Schris.kirby@sun.com */ 352010242Schris.kirby@sun.com static int 352110242Schris.kirby@sun.com zfs_ioc_get_holds(zfs_cmd_t *zc) 352210242Schris.kirby@sun.com { 352310242Schris.kirby@sun.com nvlist_t *nvp; 352410242Schris.kirby@sun.com int error; 352510242Schris.kirby@sun.com 352610242Schris.kirby@sun.com if ((error = dsl_dataset_get_holds(zc->zc_name, &nvp)) == 0) { 352710242Schris.kirby@sun.com error = put_nvlist(zc, nvp); 352810242Schris.kirby@sun.com nvlist_free(nvp); 352910242Schris.kirby@sun.com } 353010242Schris.kirby@sun.com 353110242Schris.kirby@sun.com return (error); 353210242Schris.kirby@sun.com } 353310242Schris.kirby@sun.com 353410242Schris.kirby@sun.com /* 35354988Sek110237 * pool create, destroy, and export don't log the history as part of 35364988Sek110237 * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 35374988Sek110237 * do the logging of those commands. 35384543Smarks */ 3539789Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 35409234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35419234SGeorge.Wilson@Sun.COM B_FALSE }, 35429234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35439234SGeorge.Wilson@Sun.COM B_FALSE }, 35449234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35459234SGeorge.Wilson@Sun.COM B_FALSE }, 35469234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35479234SGeorge.Wilson@Sun.COM B_FALSE }, 35489234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE, 35499234SGeorge.Wilson@Sun.COM B_FALSE }, 35509234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE, 35519234SGeorge.Wilson@Sun.COM B_FALSE }, 35529234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE, 35539234SGeorge.Wilson@Sun.COM B_FALSE }, 35549234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35559234SGeorge.Wilson@Sun.COM B_TRUE }, 35569234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, 35579234SGeorge.Wilson@Sun.COM B_FALSE }, 35589234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35599234SGeorge.Wilson@Sun.COM B_TRUE }, 35609234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35619234SGeorge.Wilson@Sun.COM B_FALSE }, 35629234SGeorge.Wilson@Sun.COM { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35639234SGeorge.Wilson@Sun.COM B_TRUE }, 35649234SGeorge.Wilson@Sun.COM { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35659234SGeorge.Wilson@Sun.COM B_TRUE }, 35669234SGeorge.Wilson@Sun.COM { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35679234SGeorge.Wilson@Sun.COM B_FALSE }, 35689234SGeorge.Wilson@Sun.COM { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35699234SGeorge.Wilson@Sun.COM B_TRUE }, 35709234SGeorge.Wilson@Sun.COM { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 35719234SGeorge.Wilson@Sun.COM B_TRUE }, 35729234SGeorge.Wilson@Sun.COM { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35739234SGeorge.Wilson@Sun.COM B_TRUE }, 35749425SEric.Schrock@Sun.COM { zfs_ioc_vdev_setfru, zfs_secpolicy_config, POOL_NAME, B_FALSE, 35759425SEric.Schrock@Sun.COM B_TRUE }, 35769234SGeorge.Wilson@Sun.COM { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 35779234SGeorge.Wilson@Sun.COM B_FALSE }, 35789234SGeorge.Wilson@Sun.COM { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 35799234SGeorge.Wilson@Sun.COM B_FALSE }, 35809234SGeorge.Wilson@Sun.COM { zfs_ioc_dataset_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 35819234SGeorge.Wilson@Sun.COM B_FALSE }, 35829234SGeorge.Wilson@Sun.COM { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 35839234SGeorge.Wilson@Sun.COM B_FALSE }, 35849234SGeorge.Wilson@Sun.COM { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, B_TRUE }, 35859234SGeorge.Wilson@Sun.COM { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE, 35869234SGeorge.Wilson@Sun.COM B_FALSE }, 35879234SGeorge.Wilson@Sun.COM { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE, 35889234SGeorge.Wilson@Sun.COM B_FALSE }, 35899234SGeorge.Wilson@Sun.COM { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, B_TRUE }, 35909234SGeorge.Wilson@Sun.COM { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 35919234SGeorge.Wilson@Sun.COM B_TRUE}, 35929234SGeorge.Wilson@Sun.COM { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE, 35939234SGeorge.Wilson@Sun.COM B_TRUE }, 35949234SGeorge.Wilson@Sun.COM { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE, B_TRUE }, 35959234SGeorge.Wilson@Sun.COM { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE, B_TRUE }, 35969234SGeorge.Wilson@Sun.COM { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE, B_FALSE }, 35979234SGeorge.Wilson@Sun.COM { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 35989234SGeorge.Wilson@Sun.COM B_FALSE }, 35999234SGeorge.Wilson@Sun.COM { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 36009234SGeorge.Wilson@Sun.COM B_FALSE }, 36019234SGeorge.Wilson@Sun.COM { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE, 36029234SGeorge.Wilson@Sun.COM B_FALSE }, 36039234SGeorge.Wilson@Sun.COM { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE, 36049234SGeorge.Wilson@Sun.COM B_FALSE }, 36059234SGeorge.Wilson@Sun.COM { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE, B_FALSE }, 36069234SGeorge.Wilson@Sun.COM { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE, 36079234SGeorge.Wilson@Sun.COM B_TRUE }, 36089234SGeorge.Wilson@Sun.COM { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 36099234SGeorge.Wilson@Sun.COM B_TRUE }, 36109234SGeorge.Wilson@Sun.COM { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE, 36119234SGeorge.Wilson@Sun.COM B_TRUE }, 36129234SGeorge.Wilson@Sun.COM { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE, 36139234SGeorge.Wilson@Sun.COM B_FALSE }, 361410233SGeorge.Wilson@Sun.COM { zfs_ioc_obj_to_path, zfs_secpolicy_config, DATASET_NAME, B_FALSE, 361510233SGeorge.Wilson@Sun.COM B_TRUE }, 36169234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE, 36179234SGeorge.Wilson@Sun.COM B_TRUE }, 36189234SGeorge.Wilson@Sun.COM { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE, 36199234SGeorge.Wilson@Sun.COM B_FALSE }, 36209234SGeorge.Wilson@Sun.COM { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE, 36219234SGeorge.Wilson@Sun.COM B_TRUE }, 36229234SGeorge.Wilson@Sun.COM { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 36239234SGeorge.Wilson@Sun.COM B_FALSE }, 36249234SGeorge.Wilson@Sun.COM { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, DATASET_NAME, B_FALSE, 36259234SGeorge.Wilson@Sun.COM B_FALSE }, 36269234SGeorge.Wilson@Sun.COM { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE, B_FALSE }, 36279234SGeorge.Wilson@Sun.COM { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE, 36289234SGeorge.Wilson@Sun.COM B_TRUE }, 36299234SGeorge.Wilson@Sun.COM { zfs_ioc_smb_acl, zfs_secpolicy_smb_acl, DATASET_NAME, B_FALSE, 36309396SMatthew.Ahrens@Sun.COM B_FALSE }, 36319396SMatthew.Ahrens@Sun.COM { zfs_ioc_userspace_one, zfs_secpolicy_userspace_one, 36329396SMatthew.Ahrens@Sun.COM DATASET_NAME, B_FALSE, B_FALSE }, 36339396SMatthew.Ahrens@Sun.COM { zfs_ioc_userspace_many, zfs_secpolicy_userspace_many, 36349396SMatthew.Ahrens@Sun.COM DATASET_NAME, B_FALSE, B_FALSE }, 36359396SMatthew.Ahrens@Sun.COM { zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 36369396SMatthew.Ahrens@Sun.COM DATASET_NAME, B_FALSE, B_TRUE }, 363710242Schris.kirby@sun.com { zfs_ioc_hold, zfs_secpolicy_hold, DATASET_NAME, B_TRUE, B_TRUE }, 363810242Schris.kirby@sun.com { zfs_ioc_release, zfs_secpolicy_release, DATASET_NAME, B_TRUE, 363910242Schris.kirby@sun.com B_TRUE }, 364010242Schris.kirby@sun.com { zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 364110242Schris.kirby@sun.com B_TRUE } 3642789Sahrens }; 3643789Sahrens 36449234SGeorge.Wilson@Sun.COM int 36459234SGeorge.Wilson@Sun.COM pool_status_check(const char *name, zfs_ioc_namecheck_t type) 36469234SGeorge.Wilson@Sun.COM { 36479234SGeorge.Wilson@Sun.COM spa_t *spa; 36489234SGeorge.Wilson@Sun.COM int error; 36499234SGeorge.Wilson@Sun.COM 36509234SGeorge.Wilson@Sun.COM ASSERT(type == POOL_NAME || type == DATASET_NAME); 36519234SGeorge.Wilson@Sun.COM 36529396SMatthew.Ahrens@Sun.COM error = spa_open(name, &spa, FTAG); 36539234SGeorge.Wilson@Sun.COM if (error == 0) { 36549234SGeorge.Wilson@Sun.COM if (spa_suspended(spa)) 36559234SGeorge.Wilson@Sun.COM error = EAGAIN; 36569234SGeorge.Wilson@Sun.COM spa_close(spa, FTAG); 36579234SGeorge.Wilson@Sun.COM } 36589234SGeorge.Wilson@Sun.COM return (error); 36599234SGeorge.Wilson@Sun.COM } 36609234SGeorge.Wilson@Sun.COM 3661789Sahrens static int 3662789Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 3663789Sahrens { 3664789Sahrens zfs_cmd_t *zc; 3665789Sahrens uint_t vec; 36662199Sahrens int error, rc; 3667789Sahrens 3668789Sahrens if (getminor(dev) != 0) 3669789Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 3670789Sahrens 3671789Sahrens vec = cmd - ZFS_IOC; 36724787Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 3673789Sahrens 3674789Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 3675789Sahrens return (EINVAL); 3676789Sahrens 3677789Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 3678789Sahrens 36799643SEric.Taylor@Sun.COM error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag); 3680789Sahrens 36814787Sahrens if (error == 0) 36824543Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 3683789Sahrens 3684789Sahrens /* 3685789Sahrens * Ensure that all pool/dataset names are valid before we pass down to 3686789Sahrens * the lower layers. 3687789Sahrens */ 3688789Sahrens if (error == 0) { 3689789Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 36909643SEric.Taylor@Sun.COM zc->zc_iflags = flag & FKIOCTL; 3691789Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 36924577Sahrens case POOL_NAME: 3693789Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 3694789Sahrens error = EINVAL; 36959234SGeorge.Wilson@Sun.COM if (zfs_ioc_vec[vec].zvec_pool_check) 36969234SGeorge.Wilson@Sun.COM error = pool_status_check(zc->zc_name, 36979234SGeorge.Wilson@Sun.COM zfs_ioc_vec[vec].zvec_namecheck); 3698789Sahrens break; 3699789Sahrens 37004577Sahrens case DATASET_NAME: 3701789Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 3702789Sahrens error = EINVAL; 37039234SGeorge.Wilson@Sun.COM if (zfs_ioc_vec[vec].zvec_pool_check) 37049234SGeorge.Wilson@Sun.COM error = pool_status_check(zc->zc_name, 37059234SGeorge.Wilson@Sun.COM zfs_ioc_vec[vec].zvec_namecheck); 3706789Sahrens break; 37072856Snd150628 37084577Sahrens case NO_NAME: 37092856Snd150628 break; 3710789Sahrens } 3711789Sahrens } 3712789Sahrens 3713789Sahrens if (error == 0) 3714789Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 3715789Sahrens 37169643SEric.Taylor@Sun.COM rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag); 37174543Smarks if (error == 0) { 37182199Sahrens error = rc; 37199396SMatthew.Ahrens@Sun.COM if (zfs_ioc_vec[vec].zvec_his_log) 37204543Smarks zfs_log_history(zc); 37214543Smarks } 3722789Sahrens 3723789Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 3724789Sahrens return (error); 3725789Sahrens } 3726789Sahrens 3727789Sahrens static int 3728789Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3729789Sahrens { 3730789Sahrens if (cmd != DDI_ATTACH) 3731789Sahrens return (DDI_FAILURE); 3732789Sahrens 3733789Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 3734789Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 3735789Sahrens return (DDI_FAILURE); 3736789Sahrens 3737789Sahrens zfs_dip = dip; 3738789Sahrens 3739789Sahrens ddi_report_dev(dip); 3740789Sahrens 3741789Sahrens return (DDI_SUCCESS); 3742789Sahrens } 3743789Sahrens 3744789Sahrens static int 3745789Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3746789Sahrens { 3747789Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 3748789Sahrens return (DDI_FAILURE); 3749789Sahrens 3750789Sahrens if (cmd != DDI_DETACH) 3751789Sahrens return (DDI_FAILURE); 3752789Sahrens 3753789Sahrens zfs_dip = NULL; 3754789Sahrens 3755789Sahrens ddi_prop_remove_all(dip); 3756789Sahrens ddi_remove_minor_node(dip, NULL); 3757789Sahrens 3758789Sahrens return (DDI_SUCCESS); 3759789Sahrens } 3760789Sahrens 3761789Sahrens /*ARGSUSED*/ 3762789Sahrens static int 3763789Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3764789Sahrens { 3765789Sahrens switch (infocmd) { 3766789Sahrens case DDI_INFO_DEVT2DEVINFO: 3767789Sahrens *result = zfs_dip; 3768789Sahrens return (DDI_SUCCESS); 3769789Sahrens 3770789Sahrens case DDI_INFO_DEVT2INSTANCE: 3771849Sbonwick *result = (void *)0; 3772789Sahrens return (DDI_SUCCESS); 3773789Sahrens } 3774789Sahrens 3775789Sahrens return (DDI_FAILURE); 3776789Sahrens } 3777789Sahrens 3778789Sahrens /* 3779789Sahrens * OK, so this is a little weird. 3780789Sahrens * 3781789Sahrens * /dev/zfs is the control node, i.e. minor 0. 3782789Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3783789Sahrens * 3784789Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 3785789Sahrens * so most of the standard driver entry points are in zvol.c. 3786789Sahrens */ 3787789Sahrens static struct cb_ops zfs_cb_ops = { 3788789Sahrens zvol_open, /* open */ 3789789Sahrens zvol_close, /* close */ 3790789Sahrens zvol_strategy, /* strategy */ 3791789Sahrens nodev, /* print */ 37926423Sgw25295 zvol_dump, /* dump */ 3793789Sahrens zvol_read, /* read */ 3794789Sahrens zvol_write, /* write */ 3795789Sahrens zfsdev_ioctl, /* ioctl */ 3796789Sahrens nodev, /* devmap */ 3797789Sahrens nodev, /* mmap */ 3798789Sahrens nodev, /* segmap */ 3799789Sahrens nochpoll, /* poll */ 3800789Sahrens ddi_prop_op, /* prop_op */ 3801789Sahrens NULL, /* streamtab */ 3802789Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 3803789Sahrens CB_REV, /* version */ 38043638Sbillm nodev, /* async read */ 38053638Sbillm nodev, /* async write */ 3806789Sahrens }; 3807789Sahrens 3808789Sahrens static struct dev_ops zfs_dev_ops = { 3809789Sahrens DEVO_REV, /* version */ 3810789Sahrens 0, /* refcnt */ 3811789Sahrens zfs_info, /* info */ 3812789Sahrens nulldev, /* identify */ 3813789Sahrens nulldev, /* probe */ 3814789Sahrens zfs_attach, /* attach */ 3815789Sahrens zfs_detach, /* detach */ 3816789Sahrens nodev, /* reset */ 3817789Sahrens &zfs_cb_ops, /* driver operations */ 38187656SSherry.Moore@Sun.COM NULL, /* no bus operations */ 38197656SSherry.Moore@Sun.COM NULL, /* power */ 38207656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 3821789Sahrens }; 3822789Sahrens 3823789Sahrens static struct modldrv zfs_modldrv = { 38247656SSherry.Moore@Sun.COM &mod_driverops, 38257656SSherry.Moore@Sun.COM "ZFS storage pool", 38267656SSherry.Moore@Sun.COM &zfs_dev_ops 3827789Sahrens }; 3828789Sahrens 3829789Sahrens static struct modlinkage modlinkage = { 3830789Sahrens MODREV_1, 3831789Sahrens (void *)&zfs_modlfs, 3832789Sahrens (void *)&zfs_modldrv, 3833789Sahrens NULL 3834789Sahrens }; 3835789Sahrens 38364720Sfr157268 38374720Sfr157268 uint_t zfs_fsyncer_key; 38385326Sek110237 extern uint_t rrw_tsd_key; 38394720Sfr157268 3840789Sahrens int 3841789Sahrens _init(void) 3842789Sahrens { 3843789Sahrens int error; 3844789Sahrens 3845849Sbonwick spa_init(FREAD | FWRITE); 3846849Sbonwick zfs_init(); 3847849Sbonwick zvol_init(); 3848849Sbonwick 3849849Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 3850849Sbonwick zvol_fini(); 3851849Sbonwick zfs_fini(); 3852849Sbonwick spa_fini(); 3853789Sahrens return (error); 3854849Sbonwick } 3855789Sahrens 38564720Sfr157268 tsd_create(&zfs_fsyncer_key, NULL); 38575326Sek110237 tsd_create(&rrw_tsd_key, NULL); 38584720Sfr157268 3859789Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 3860789Sahrens ASSERT(error == 0); 38614543Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3862789Sahrens 3863789Sahrens return (0); 3864789Sahrens } 3865789Sahrens 3866789Sahrens int 3867789Sahrens _fini(void) 3868789Sahrens { 3869789Sahrens int error; 3870789Sahrens 38711544Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3872789Sahrens return (EBUSY); 3873789Sahrens 3874789Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3875789Sahrens return (error); 3876789Sahrens 3877789Sahrens zvol_fini(); 3878789Sahrens zfs_fini(); 3879789Sahrens spa_fini(); 38805331Samw if (zfs_nfsshare_inited) 38814543Smarks (void) ddi_modclose(nfs_mod); 38825331Samw if (zfs_smbshare_inited) 38835331Samw (void) ddi_modclose(smbsrv_mod); 38845331Samw if (zfs_nfsshare_inited || zfs_smbshare_inited) 38854543Smarks (void) ddi_modclose(sharefs_mod); 3886789Sahrens 38874720Sfr157268 tsd_destroy(&zfs_fsyncer_key); 3888789Sahrens ldi_ident_release(zfs_li); 3889789Sahrens zfs_li = NULL; 38904543Smarks mutex_destroy(&zfs_share_lock); 3891789Sahrens 3892789Sahrens return (error); 3893789Sahrens } 3894789Sahrens 3895789Sahrens int 3896789Sahrens _info(struct modinfo *modinfop) 3897789Sahrens { 3898789Sahrens return (mod_info(&modlinkage, modinfop)); 3899789Sahrens } 3900