1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22379c004dSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/types.h> 27fa9e4066Sahrens #include <sys/param.h> 28fa9e4066Sahrens #include <sys/errno.h> 29fa9e4066Sahrens #include <sys/uio.h> 30fa9e4066Sahrens #include <sys/buf.h> 31fa9e4066Sahrens #include <sys/modctl.h> 32fa9e4066Sahrens #include <sys/open.h> 33fa9e4066Sahrens #include <sys/file.h> 34fa9e4066Sahrens #include <sys/kmem.h> 35fa9e4066Sahrens #include <sys/conf.h> 36fa9e4066Sahrens #include <sys/cmn_err.h> 37fa9e4066Sahrens #include <sys/stat.h> 38fa9e4066Sahrens #include <sys/zfs_ioctl.h> 39da6c28aaSamw #include <sys/zfs_znode.h> 40fa9e4066Sahrens #include <sys/zap.h> 41fa9e4066Sahrens #include <sys/spa.h> 42b1b8ab34Slling #include <sys/spa_impl.h> 43fa9e4066Sahrens #include <sys/vdev.h> 44b1b8ab34Slling #include <sys/vdev_impl.h> 45fa9e4066Sahrens #include <sys/dmu.h> 46fa9e4066Sahrens #include <sys/dsl_dir.h> 47fa9e4066Sahrens #include <sys/dsl_dataset.h> 48fa9e4066Sahrens #include <sys/dsl_prop.h> 49ecd6cf80Smarks #include <sys/dsl_deleg.h> 50ecd6cf80Smarks #include <sys/dmu_objset.h> 51fa9e4066Sahrens #include <sys/ddi.h> 52fa9e4066Sahrens #include <sys/sunddi.h> 53fa9e4066Sahrens #include <sys/sunldi.h> 54fa9e4066Sahrens #include <sys/policy.h> 55fa9e4066Sahrens #include <sys/zone.h> 56fa9e4066Sahrens #include <sys/nvpair.h> 57fa9e4066Sahrens #include <sys/pathname.h> 58fa9e4066Sahrens #include <sys/mount.h> 59fa9e4066Sahrens #include <sys/sdt.h> 60fa9e4066Sahrens #include <sys/fs/zfs.h> 61fa9e4066Sahrens #include <sys/zfs_ctldir.h> 62da6c28aaSamw #include <sys/zfs_dir.h> 63a2eea2e1Sahrens #include <sys/zvol.h> 64ecd6cf80Smarks #include <sharefs/share.h> 65f18faf3fSek #include <sys/dmu_objset.h> 66fa9e4066Sahrens 67fa9e4066Sahrens #include "zfs_namecheck.h" 68e9dbad6fSeschrock #include "zfs_prop.h" 69ecd6cf80Smarks #include "zfs_deleg.h" 70fa9e4066Sahrens 71fa9e4066Sahrens extern struct modlfs zfs_modlfs; 72fa9e4066Sahrens 73fa9e4066Sahrens extern void zfs_init(void); 74fa9e4066Sahrens extern void zfs_fini(void); 75fa9e4066Sahrens 76fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 77fa9e4066Sahrens dev_info_t *zfs_dip; 78fa9e4066Sahrens 79fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *); 80ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 81fa9e4066Sahrens 82fa9e4066Sahrens typedef struct zfs_ioc_vec { 83fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 84fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 85fa9e4066Sahrens enum { 86e7437265Sahrens NO_NAME, 87e7437265Sahrens POOL_NAME, 88e7437265Sahrens DATASET_NAME 89ecd6cf80Smarks } zvec_namecheck; 90ecd6cf80Smarks boolean_t zvec_his_log; 91fa9e4066Sahrens } zfs_ioc_vec_t; 92fa9e4066Sahrens 936e77af0aSDavid Pacheco static void clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops); 940a48a24eStimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 950a48a24eStimh boolean_t *); 960a48a24eStimh int zfs_set_prop_nvlist(const char *, nvlist_t *); 970a48a24eStimh 98fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 99fa9e4066Sahrens void 100fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 101fa9e4066Sahrens { 102fa9e4066Sahrens const char *newfile; 103fa9e4066Sahrens char buf[256]; 104fa9e4066Sahrens va_list adx; 105fa9e4066Sahrens 106fa9e4066Sahrens /* 107fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 108fa9e4066Sahrens */ 109fa9e4066Sahrens newfile = strrchr(file, '/'); 110fa9e4066Sahrens if (newfile != NULL) { 111fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 112fa9e4066Sahrens } else { 113fa9e4066Sahrens newfile = file; 114fa9e4066Sahrens } 115fa9e4066Sahrens 116fa9e4066Sahrens va_start(adx, fmt); 117fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 118fa9e4066Sahrens va_end(adx); 119fa9e4066Sahrens 120fa9e4066Sahrens /* 121fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 122fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 123fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 124fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 125fa9e4066Sahrens * arg0 = file name 126fa9e4066Sahrens * arg1 = function name 127fa9e4066Sahrens * arg2 = line number 128fa9e4066Sahrens * arg3 = message 129fa9e4066Sahrens */ 130fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 131fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 132fa9e4066Sahrens } 133fa9e4066Sahrens 134ecd6cf80Smarks static void 135228975ccSek history_str_free(char *buf) 136228975ccSek { 137228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 138228975ccSek } 139228975ccSek 140228975ccSek static char * 141228975ccSek history_str_get(zfs_cmd_t *zc) 142ecd6cf80Smarks { 14340feaa91Sahrens char *buf; 144ecd6cf80Smarks 145ecd6cf80Smarks if (zc->zc_history == NULL) 146228975ccSek return (NULL); 147e7437265Sahrens 148ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 149ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 150ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 151228975ccSek history_str_free(buf); 152228975ccSek return (NULL); 153ecd6cf80Smarks } 154ecd6cf80Smarks 155ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 156ecd6cf80Smarks 157228975ccSek return (buf); 158228975ccSek } 159ecd6cf80Smarks 16015e6edf1Sgw /* 16115e6edf1Sgw * Check to see if the named dataset is currently defined as bootable 16215e6edf1Sgw */ 16315e6edf1Sgw static boolean_t 16415e6edf1Sgw zfs_is_bootfs(const char *name) 16515e6edf1Sgw { 16615e6edf1Sgw spa_t *spa; 16715e6edf1Sgw boolean_t ret = B_FALSE; 16815e6edf1Sgw 16915e6edf1Sgw if (spa_open(name, &spa, FTAG) == 0) { 17015e6edf1Sgw if (spa->spa_bootfs) { 17115e6edf1Sgw objset_t *os; 17215e6edf1Sgw 17315e6edf1Sgw if (dmu_objset_open(name, DMU_OST_ZFS, 17415e6edf1Sgw DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 17515e6edf1Sgw ret = (dmu_objset_id(os) == spa->spa_bootfs); 17615e6edf1Sgw dmu_objset_close(os); 17715e6edf1Sgw } 17815e6edf1Sgw } 17915e6edf1Sgw spa_close(spa, FTAG); 18015e6edf1Sgw } 18115e6edf1Sgw return (ret); 18215e6edf1Sgw } 18315e6edf1Sgw 184c2a93d44Stimh /* 1850a48a24eStimh * zfs_earlier_version 186c2a93d44Stimh * 187c2a93d44Stimh * Return non-zero if the spa version is less than requested version. 188c2a93d44Stimh */ 189da6c28aaSamw static int 1900a48a24eStimh zfs_earlier_version(const char *name, int version) 191da6c28aaSamw { 192da6c28aaSamw spa_t *spa; 193da6c28aaSamw 194da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 195da6c28aaSamw if (spa_version(spa) < version) { 196da6c28aaSamw spa_close(spa, FTAG); 197da6c28aaSamw return (1); 198da6c28aaSamw } 199da6c28aaSamw spa_close(spa, FTAG); 200da6c28aaSamw } 201da6c28aaSamw return (0); 202da6c28aaSamw } 203da6c28aaSamw 2049e6eda55Smarks /* 205745cd3c5Smaybee * zpl_earlier_version 2069e6eda55Smarks * 207745cd3c5Smaybee * Return TRUE if the ZPL version is less than requested version. 2089e6eda55Smarks */ 209745cd3c5Smaybee static boolean_t 210745cd3c5Smaybee zpl_earlier_version(const char *name, int version) 2119e6eda55Smarks { 2129e6eda55Smarks objset_t *os; 213745cd3c5Smaybee boolean_t rc = B_TRUE; 2149e6eda55Smarks 2159e6eda55Smarks if (dmu_objset_open(name, DMU_OST_ANY, 216745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 217745cd3c5Smaybee uint64_t zplversion; 2189e6eda55Smarks 219745cd3c5Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 220745cd3c5Smaybee rc = zplversion < version; 2219e6eda55Smarks dmu_objset_close(os); 2229e6eda55Smarks } 2239e6eda55Smarks return (rc); 2249e6eda55Smarks } 2259e6eda55Smarks 226228975ccSek static void 227228975ccSek zfs_log_history(zfs_cmd_t *zc) 228228975ccSek { 229228975ccSek spa_t *spa; 230228975ccSek char *buf; 231ecd6cf80Smarks 232228975ccSek if ((buf = history_str_get(zc)) == NULL) 233228975ccSek return; 234228975ccSek 235228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 236228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 237228975ccSek (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 238228975ccSek spa_close(spa, FTAG); 239228975ccSek } 240228975ccSek history_str_free(buf); 241ecd6cf80Smarks } 242ecd6cf80Smarks 243fa9e4066Sahrens /* 244fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 245fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 246fa9e4066Sahrens */ 247fa9e4066Sahrens /* ARGSUSED */ 248fa9e4066Sahrens static int 249ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 250fa9e4066Sahrens { 251fa9e4066Sahrens return (0); 252fa9e4066Sahrens } 253fa9e4066Sahrens 254fa9e4066Sahrens /* 255fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 256fa9e4066Sahrens * no privileges, but must be visible in the local zone. 257fa9e4066Sahrens */ 258fa9e4066Sahrens /* ARGSUSED */ 259fa9e4066Sahrens static int 260ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 261fa9e4066Sahrens { 262fa9e4066Sahrens if (INGLOBALZONE(curproc) || 263ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 264fa9e4066Sahrens return (0); 265fa9e4066Sahrens 266fa9e4066Sahrens return (ENOENT); 267fa9e4066Sahrens } 268fa9e4066Sahrens 269fa9e4066Sahrens static int 270fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr) 271fa9e4066Sahrens { 272fa9e4066Sahrens uint64_t zoned; 273fa9e4066Sahrens int writable = 1; 274fa9e4066Sahrens 275fa9e4066Sahrens /* 276fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 277fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 278fa9e4066Sahrens */ 279fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 280fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 281fa9e4066Sahrens return (ENOENT); 282fa9e4066Sahrens 283fa9e4066Sahrens if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 284fa9e4066Sahrens return (ENOENT); 285fa9e4066Sahrens 286fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 287fa9e4066Sahrens /* 288fa9e4066Sahrens * If the fs is zoned, only root can access it from the 289fa9e4066Sahrens * global zone. 290fa9e4066Sahrens */ 291fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 292fa9e4066Sahrens return (EPERM); 293fa9e4066Sahrens } else { 294fa9e4066Sahrens /* 295fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 296fa9e4066Sahrens */ 297fa9e4066Sahrens if (!zoned) 298fa9e4066Sahrens return (EPERM); 299fa9e4066Sahrens 300fa9e4066Sahrens /* must be writable by this zone */ 301fa9e4066Sahrens if (!writable) 302fa9e4066Sahrens return (EPERM); 303fa9e4066Sahrens } 304fa9e4066Sahrens return (0); 305fa9e4066Sahrens } 306fa9e4066Sahrens 307fa9e4066Sahrens int 308ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 309fa9e4066Sahrens { 310fa9e4066Sahrens int error; 311fa9e4066Sahrens 312ecd6cf80Smarks error = zfs_dozonecheck(name, cr); 313ecd6cf80Smarks if (error == 0) { 314ecd6cf80Smarks error = secpolicy_zfs(cr); 315db870a07Sahrens if (error) 316ecd6cf80Smarks error = dsl_deleg_access(name, perm, cr); 317ecd6cf80Smarks } 318ecd6cf80Smarks return (error); 319ecd6cf80Smarks } 320ecd6cf80Smarks 321ecd6cf80Smarks static int 322ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 323ecd6cf80Smarks { 324ecd6cf80Smarks /* 325ecd6cf80Smarks * Check permissions for special properties. 326ecd6cf80Smarks */ 327ecd6cf80Smarks switch (prop) { 328ecd6cf80Smarks case ZFS_PROP_ZONED: 329ecd6cf80Smarks /* 330ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 331ecd6cf80Smarks */ 332ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 333ecd6cf80Smarks return (EPERM); 334ecd6cf80Smarks break; 335ecd6cf80Smarks 336ecd6cf80Smarks case ZFS_PROP_QUOTA: 337ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 338ecd6cf80Smarks uint64_t zoned; 339ecd6cf80Smarks char setpoint[MAXNAMELEN]; 340ecd6cf80Smarks /* 341ecd6cf80Smarks * Unprivileged users are allowed to modify the 342ecd6cf80Smarks * quota on things *under* (ie. contained by) 343ecd6cf80Smarks * the thing they own. 344ecd6cf80Smarks */ 345ecd6cf80Smarks if (dsl_prop_get_integer(name, "zoned", &zoned, 346ecd6cf80Smarks setpoint)) 347ecd6cf80Smarks return (EPERM); 348db870a07Sahrens if (!zoned || strlen(name) <= strlen(setpoint)) 349ecd6cf80Smarks return (EPERM); 350ecd6cf80Smarks } 351db870a07Sahrens break; 352ecd6cf80Smarks } 353ecd6cf80Smarks 35491ebeef5Sahrens return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 355ecd6cf80Smarks } 356ecd6cf80Smarks 357ecd6cf80Smarks int 358ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 359ecd6cf80Smarks { 360ecd6cf80Smarks int error; 361ecd6cf80Smarks 362ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 363ecd6cf80Smarks if (error) 364fa9e4066Sahrens return (error); 365fa9e4066Sahrens 366ecd6cf80Smarks /* 367ecd6cf80Smarks * permission to set permissions will be evaluated later in 368ecd6cf80Smarks * dsl_deleg_can_allow() 369ecd6cf80Smarks */ 370ecd6cf80Smarks return (0); 371ecd6cf80Smarks } 372ecd6cf80Smarks 373ecd6cf80Smarks int 374ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 375ecd6cf80Smarks { 376ecd6cf80Smarks int error; 377ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 378ecd6cf80Smarks ZFS_DELEG_PERM_ROLLBACK, cr); 379ecd6cf80Smarks if (error == 0) 380ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 381ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 382ecd6cf80Smarks return (error); 383ecd6cf80Smarks } 384ecd6cf80Smarks 385ecd6cf80Smarks int 386ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 387ecd6cf80Smarks { 388ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 389ecd6cf80Smarks ZFS_DELEG_PERM_SEND, cr)); 390ecd6cf80Smarks } 391ecd6cf80Smarks 392*743a77edSAlan Wright static int 393*743a77edSAlan Wright zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) 394*743a77edSAlan Wright { 395*743a77edSAlan Wright vnode_t *vp; 396*743a77edSAlan Wright int error; 397*743a77edSAlan Wright 398*743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 399*743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 400*743a77edSAlan Wright return (error); 401*743a77edSAlan Wright 402*743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 403*743a77edSAlan Wright 404*743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 405*743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 406*743a77edSAlan Wright zc->zc_name) != 0)) { 407*743a77edSAlan Wright VN_RELE(vp); 408*743a77edSAlan Wright return (EPERM); 409*743a77edSAlan Wright } 410*743a77edSAlan Wright 411*743a77edSAlan Wright VN_RELE(vp); 412*743a77edSAlan Wright return (dsl_deleg_access(zc->zc_name, 413*743a77edSAlan Wright ZFS_DELEG_PERM_SHARE, cr)); 414*743a77edSAlan Wright } 415*743a77edSAlan Wright 416ecd6cf80Smarks int 417ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 418ecd6cf80Smarks { 419ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 420ecd6cf80Smarks return (EPERM); 421ecd6cf80Smarks 4223cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 423ecd6cf80Smarks return (0); 424ecd6cf80Smarks } else { 425*743a77edSAlan Wright return (zfs_secpolicy_deleg_share(zc, cr)); 426*743a77edSAlan Wright } 427*743a77edSAlan Wright } 428ecd6cf80Smarks 429*743a77edSAlan Wright int 430*743a77edSAlan Wright zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) 431*743a77edSAlan Wright { 432*743a77edSAlan Wright if (!INGLOBALZONE(curproc)) 433*743a77edSAlan Wright return (EPERM); 434ecd6cf80Smarks 435*743a77edSAlan Wright if (secpolicy_smb(cr) == 0) { 436*743a77edSAlan Wright return (0); 437*743a77edSAlan Wright } else { 438*743a77edSAlan Wright return (zfs_secpolicy_deleg_share(zc, cr)); 439ecd6cf80Smarks } 440fa9e4066Sahrens } 441fa9e4066Sahrens 442fa9e4066Sahrens static int 443ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 444fa9e4066Sahrens { 445fa9e4066Sahrens char *cp; 446fa9e4066Sahrens 447fa9e4066Sahrens /* 448fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 449fa9e4066Sahrens */ 450ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 451ecd6cf80Smarks cp = strrchr(parent, '@'); 452fa9e4066Sahrens if (cp != NULL) { 453fa9e4066Sahrens cp[0] = '\0'; 454fa9e4066Sahrens } else { 455ecd6cf80Smarks cp = strrchr(parent, '/'); 456fa9e4066Sahrens if (cp == NULL) 457fa9e4066Sahrens return (ENOENT); 458fa9e4066Sahrens cp[0] = '\0'; 459ecd6cf80Smarks } 460ecd6cf80Smarks 461ecd6cf80Smarks return (0); 462ecd6cf80Smarks } 463ecd6cf80Smarks 464ecd6cf80Smarks int 465ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 466ecd6cf80Smarks { 467ecd6cf80Smarks int error; 468ecd6cf80Smarks 469ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 470ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 471ecd6cf80Smarks return (error); 472ecd6cf80Smarks 473ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 474ecd6cf80Smarks } 475ecd6cf80Smarks 476ecd6cf80Smarks static int 477ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 478ecd6cf80Smarks { 479ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 480ecd6cf80Smarks } 481ecd6cf80Smarks 482ecd6cf80Smarks /* 483ecd6cf80Smarks * Must have sys_config privilege to check the iscsi permission 484ecd6cf80Smarks */ 485ecd6cf80Smarks /* ARGSUSED */ 486ecd6cf80Smarks static int 487ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 488ecd6cf80Smarks { 489ecd6cf80Smarks return (secpolicy_zfs(cr)); 490ecd6cf80Smarks } 491ecd6cf80Smarks 492ecd6cf80Smarks int 493ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 494ecd6cf80Smarks { 495ecd6cf80Smarks char parentname[MAXNAMELEN]; 496ecd6cf80Smarks int error; 497ecd6cf80Smarks 498ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 499ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 500ecd6cf80Smarks return (error); 501ecd6cf80Smarks 502ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 503ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 504ecd6cf80Smarks return (error); 505ecd6cf80Smarks 506ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 507ecd6cf80Smarks sizeof (parentname))) != 0) 508ecd6cf80Smarks return (error); 509ecd6cf80Smarks 510ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 511ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 512ecd6cf80Smarks return (error); 513ecd6cf80Smarks 514ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 515ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 516ecd6cf80Smarks return (error); 517ecd6cf80Smarks 518ecd6cf80Smarks return (error); 519ecd6cf80Smarks } 520ecd6cf80Smarks 521ecd6cf80Smarks static int 522ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 523ecd6cf80Smarks { 524ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 525ecd6cf80Smarks } 526ecd6cf80Smarks 527ecd6cf80Smarks static int 528ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 529ecd6cf80Smarks { 530ecd6cf80Smarks char parentname[MAXNAMELEN]; 531ecd6cf80Smarks objset_t *clone; 532ecd6cf80Smarks int error; 533ecd6cf80Smarks 534ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 535ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 536ecd6cf80Smarks if (error) 537ecd6cf80Smarks return (error); 538ecd6cf80Smarks 539ecd6cf80Smarks error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 540745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 541ecd6cf80Smarks 542ecd6cf80Smarks if (error == 0) { 543ecd6cf80Smarks dsl_dataset_t *pclone = NULL; 544ecd6cf80Smarks dsl_dir_t *dd; 545ecd6cf80Smarks dd = clone->os->os_dsl_dataset->ds_dir; 546ecd6cf80Smarks 547ecd6cf80Smarks rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 548745cd3c5Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 549745cd3c5Smaybee dd->dd_phys->dd_origin_obj, FTAG, &pclone); 550ecd6cf80Smarks rw_exit(&dd->dd_pool->dp_config_rwlock); 551ecd6cf80Smarks if (error) { 552ecd6cf80Smarks dmu_objset_close(clone); 553ecd6cf80Smarks return (error); 554ecd6cf80Smarks } 555ecd6cf80Smarks 556ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 557ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 558ecd6cf80Smarks 559ecd6cf80Smarks dsl_dataset_name(pclone, parentname); 560ecd6cf80Smarks dmu_objset_close(clone); 561745cd3c5Smaybee dsl_dataset_rele(pclone, FTAG); 562ecd6cf80Smarks if (error == 0) 563ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 564ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 565ecd6cf80Smarks } 566ecd6cf80Smarks return (error); 567ecd6cf80Smarks } 568ecd6cf80Smarks 569ecd6cf80Smarks static int 570ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 571ecd6cf80Smarks { 572ecd6cf80Smarks int error; 573ecd6cf80Smarks 574ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 575ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 576ecd6cf80Smarks return (error); 577ecd6cf80Smarks 578ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 579ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 580ecd6cf80Smarks return (error); 581ecd6cf80Smarks 582ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 583ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 584ecd6cf80Smarks } 585ecd6cf80Smarks 586ecd6cf80Smarks int 587ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 588ecd6cf80Smarks { 589ecd6cf80Smarks int error; 590ecd6cf80Smarks 591ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 592ecd6cf80Smarks ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 593ecd6cf80Smarks return (error); 594ecd6cf80Smarks 595ecd6cf80Smarks error = zfs_secpolicy_write_perms(name, 596ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 597ecd6cf80Smarks 598ecd6cf80Smarks return (error); 599ecd6cf80Smarks } 600ecd6cf80Smarks 601ecd6cf80Smarks static int 602ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 603ecd6cf80Smarks { 604ecd6cf80Smarks 605ecd6cf80Smarks return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 606ecd6cf80Smarks } 607ecd6cf80Smarks 608ecd6cf80Smarks static int 609ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 610ecd6cf80Smarks { 611ecd6cf80Smarks char parentname[MAXNAMELEN]; 612ecd6cf80Smarks int error; 613ecd6cf80Smarks 614ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 615ecd6cf80Smarks sizeof (parentname))) != 0) 616ecd6cf80Smarks return (error); 617fa9e4066Sahrens 618ecd6cf80Smarks if (zc->zc_value[0] != '\0') { 619ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_value, 620ecd6cf80Smarks ZFS_DELEG_PERM_CLONE, cr)) != 0) 621ecd6cf80Smarks return (error); 622fa9e4066Sahrens } 623fa9e4066Sahrens 624ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 625ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 626ecd6cf80Smarks return (error); 627ecd6cf80Smarks 628ecd6cf80Smarks error = zfs_secpolicy_write_perms(parentname, 629ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 630ecd6cf80Smarks 631ecd6cf80Smarks return (error); 632ecd6cf80Smarks } 633ecd6cf80Smarks 634ecd6cf80Smarks static int 635ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 636ecd6cf80Smarks { 637ecd6cf80Smarks int error; 638ecd6cf80Smarks 639ecd6cf80Smarks error = secpolicy_fs_unmount(cr, NULL); 640ecd6cf80Smarks if (error) { 641ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 642ecd6cf80Smarks } 643ecd6cf80Smarks return (error); 644fa9e4066Sahrens } 645fa9e4066Sahrens 646fa9e4066Sahrens /* 647fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 648fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 649fa9e4066Sahrens */ 650fa9e4066Sahrens /* ARGSUSED */ 651fa9e4066Sahrens static int 652ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 653fa9e4066Sahrens { 654fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 655fa9e4066Sahrens return (EPERM); 656fa9e4066Sahrens 657fa9e4066Sahrens return (0); 658fa9e4066Sahrens } 659fa9e4066Sahrens 660ecd6cf80Smarks /* 661ecd6cf80Smarks * Just like zfs_secpolicy_config, except that we will check for 662ecd6cf80Smarks * mount permission on the dataset for permission to create/remove 663ecd6cf80Smarks * the minor nodes. 664ecd6cf80Smarks */ 665ecd6cf80Smarks static int 666ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 667ecd6cf80Smarks { 668ecd6cf80Smarks if (secpolicy_sys_config(cr, B_FALSE) != 0) { 669ecd6cf80Smarks return (dsl_deleg_access(zc->zc_name, 670ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)); 671ecd6cf80Smarks } 672ecd6cf80Smarks 673ecd6cf80Smarks return (0); 674ecd6cf80Smarks } 675ecd6cf80Smarks 676ea8dc4b6Seschrock /* 677ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 678ea8dc4b6Seschrock */ 679ea8dc4b6Seschrock /* ARGSUSED */ 680ea8dc4b6Seschrock static int 681ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 682ea8dc4b6Seschrock { 683ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 684ea8dc4b6Seschrock } 685ea8dc4b6Seschrock 686e45ce728Sahrens static int 687e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 688e45ce728Sahrens { 689e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 690e45ce728Sahrens 691990b4856Slling if (prop == ZPROP_INVAL) { 692e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 693e45ce728Sahrens return (EINVAL); 694e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 695e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 696e45ce728Sahrens } else { 697e45ce728Sahrens if (!zfs_prop_inheritable(prop)) 698e45ce728Sahrens return (EINVAL); 699e45ce728Sahrens return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 700e45ce728Sahrens } 701e45ce728Sahrens } 702e45ce728Sahrens 703fa9e4066Sahrens /* 704fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 705fa9e4066Sahrens */ 706fa9e4066Sahrens static int 707990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 708fa9e4066Sahrens { 709fa9e4066Sahrens char *packed; 710fa9e4066Sahrens int error; 711990b4856Slling nvlist_t *list = NULL; 712fa9e4066Sahrens 713fa9e4066Sahrens /* 714e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 715fa9e4066Sahrens */ 716990b4856Slling if (size == 0) 717fa9e4066Sahrens return (EINVAL); 718fa9e4066Sahrens 719fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 720fa9e4066Sahrens 721990b4856Slling if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 722fa9e4066Sahrens kmem_free(packed, size); 723fa9e4066Sahrens return (error); 724fa9e4066Sahrens } 725fa9e4066Sahrens 726990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 727fa9e4066Sahrens kmem_free(packed, size); 728fa9e4066Sahrens return (error); 729fa9e4066Sahrens } 730fa9e4066Sahrens 731fa9e4066Sahrens kmem_free(packed, size); 732fa9e4066Sahrens 733990b4856Slling *nvp = list; 734fa9e4066Sahrens return (0); 735fa9e4066Sahrens } 736fa9e4066Sahrens 737e9dbad6fSeschrock static int 738e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 739e9dbad6fSeschrock { 740e9dbad6fSeschrock char *packed = NULL; 741e9dbad6fSeschrock size_t size; 742e9dbad6fSeschrock int error; 743e9dbad6fSeschrock 744e9dbad6fSeschrock VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 745e9dbad6fSeschrock 746e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 747e9dbad6fSeschrock error = ENOMEM; 748e9dbad6fSeschrock } else { 749da165920Smarks packed = kmem_alloc(size, KM_SLEEP); 750e9dbad6fSeschrock VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 751e9dbad6fSeschrock KM_SLEEP) == 0); 752e9dbad6fSeschrock error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 753e9dbad6fSeschrock size); 754e9dbad6fSeschrock kmem_free(packed, size); 755e9dbad6fSeschrock } 756e9dbad6fSeschrock 757e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 758e9dbad6fSeschrock return (error); 759e9dbad6fSeschrock } 760e9dbad6fSeschrock 761fa9e4066Sahrens static int 762fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 763fa9e4066Sahrens { 764fa9e4066Sahrens int error; 765990b4856Slling nvlist_t *config, *props = NULL; 7660a48a24eStimh nvlist_t *rootprops = NULL; 7670a48a24eStimh nvlist_t *zplprops = NULL; 768228975ccSek char *buf; 769fa9e4066Sahrens 770990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 771990b4856Slling &config)) 772fa9e4066Sahrens return (error); 7732a6b87f0Sek 774990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 775990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 776990b4856Slling nvlist_free(config); 777990b4856Slling return (error); 778990b4856Slling } 779990b4856Slling 7800a48a24eStimh if (props) { 7810a48a24eStimh nvlist_t *nvl = NULL; 7820a48a24eStimh uint64_t version = SPA_VERSION; 7830a48a24eStimh 7840a48a24eStimh (void) nvlist_lookup_uint64(props, 7850a48a24eStimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 7860a48a24eStimh if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 7870a48a24eStimh error = EINVAL; 7880a48a24eStimh goto pool_props_bad; 7890a48a24eStimh } 7900a48a24eStimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 7910a48a24eStimh if (nvl) { 7920a48a24eStimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 7930a48a24eStimh if (error != 0) { 7940a48a24eStimh nvlist_free(config); 7950a48a24eStimh nvlist_free(props); 7960a48a24eStimh return (error); 7970a48a24eStimh } 7980a48a24eStimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 7990a48a24eStimh } 8000a48a24eStimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 8010a48a24eStimh error = zfs_fill_zplprops_root(version, rootprops, 8020a48a24eStimh zplprops, NULL); 8030a48a24eStimh if (error) 8040a48a24eStimh goto pool_props_bad; 8050a48a24eStimh } 8060a48a24eStimh 8072a6b87f0Sek buf = history_str_get(zc); 808fa9e4066Sahrens 8090a48a24eStimh error = spa_create(zc->zc_name, config, props, buf, zplprops); 8100a48a24eStimh 8110a48a24eStimh /* 8120a48a24eStimh * Set the remaining root properties 8130a48a24eStimh */ 8140a48a24eStimh if (!error && 8150a48a24eStimh (error = zfs_set_prop_nvlist(zc->zc_name, rootprops)) != 0) 8160a48a24eStimh (void) spa_destroy(zc->zc_name); 817fa9e4066Sahrens 8182a6b87f0Sek if (buf != NULL) 8192a6b87f0Sek history_str_free(buf); 820990b4856Slling 8210a48a24eStimh pool_props_bad: 8220a48a24eStimh nvlist_free(rootprops); 8230a48a24eStimh nvlist_free(zplprops); 824fa9e4066Sahrens nvlist_free(config); 8250a48a24eStimh nvlist_free(props); 826990b4856Slling 827fa9e4066Sahrens return (error); 828fa9e4066Sahrens } 829fa9e4066Sahrens 830fa9e4066Sahrens static int 831fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 832fa9e4066Sahrens { 833ecd6cf80Smarks int error; 834ecd6cf80Smarks zfs_log_history(zc); 835ecd6cf80Smarks error = spa_destroy(zc->zc_name); 836ecd6cf80Smarks return (error); 837fa9e4066Sahrens } 838fa9e4066Sahrens 839fa9e4066Sahrens static int 840fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 841fa9e4066Sahrens { 842fa9e4066Sahrens int error; 843990b4856Slling nvlist_t *config, *props = NULL; 844fa9e4066Sahrens uint64_t guid; 845fa9e4066Sahrens 846990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 847990b4856Slling &config)) != 0) 848990b4856Slling return (error); 849990b4856Slling 850990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 851990b4856Slling get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 852990b4856Slling nvlist_free(config); 853fa9e4066Sahrens return (error); 854990b4856Slling } 855fa9e4066Sahrens 856fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 857ea8dc4b6Seschrock guid != zc->zc_guid) 858fa9e4066Sahrens error = EINVAL; 859c5904d13Seschrock else if (zc->zc_cookie) 860c5904d13Seschrock error = spa_import_faulted(zc->zc_name, config, 861c5904d13Seschrock props); 862fa9e4066Sahrens else 863990b4856Slling error = spa_import(zc->zc_name, config, props); 864fa9e4066Sahrens 865fa9e4066Sahrens nvlist_free(config); 866fa9e4066Sahrens 867990b4856Slling if (props) 868990b4856Slling nvlist_free(props); 869990b4856Slling 870fa9e4066Sahrens return (error); 871fa9e4066Sahrens } 872fa9e4066Sahrens 873fa9e4066Sahrens static int 874fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 875fa9e4066Sahrens { 876ecd6cf80Smarks int error; 87789a89ebfSlling boolean_t force = (boolean_t)zc->zc_cookie; 878394ab0cbSGeorge Wilson boolean_t hardforce = (boolean_t)zc->zc_guid; 87989a89ebfSlling 880ecd6cf80Smarks zfs_log_history(zc); 881394ab0cbSGeorge Wilson error = spa_export(zc->zc_name, NULL, force, hardforce); 882ecd6cf80Smarks return (error); 883fa9e4066Sahrens } 884fa9e4066Sahrens 885fa9e4066Sahrens static int 886fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 887fa9e4066Sahrens { 888fa9e4066Sahrens nvlist_t *configs; 889fa9e4066Sahrens int error; 890fa9e4066Sahrens 891fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 892fa9e4066Sahrens return (EEXIST); 893fa9e4066Sahrens 894e9dbad6fSeschrock error = put_nvlist(zc, configs); 895fa9e4066Sahrens 896fa9e4066Sahrens nvlist_free(configs); 897fa9e4066Sahrens 898fa9e4066Sahrens return (error); 899fa9e4066Sahrens } 900fa9e4066Sahrens 901fa9e4066Sahrens static int 902fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 903fa9e4066Sahrens { 904fa9e4066Sahrens nvlist_t *config; 905fa9e4066Sahrens int error; 906ea8dc4b6Seschrock int ret = 0; 907fa9e4066Sahrens 908e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 909e9dbad6fSeschrock sizeof (zc->zc_value)); 910fa9e4066Sahrens 911fa9e4066Sahrens if (config != NULL) { 912e9dbad6fSeschrock ret = put_nvlist(zc, config); 913fa9e4066Sahrens nvlist_free(config); 914ea8dc4b6Seschrock 915ea8dc4b6Seschrock /* 916ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 917ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 918ea8dc4b6Seschrock * in 'zc_cookie'. 919ea8dc4b6Seschrock */ 920ea8dc4b6Seschrock zc->zc_cookie = error; 921fa9e4066Sahrens } else { 922ea8dc4b6Seschrock ret = error; 923fa9e4066Sahrens } 924fa9e4066Sahrens 925ea8dc4b6Seschrock return (ret); 926fa9e4066Sahrens } 927fa9e4066Sahrens 928fa9e4066Sahrens /* 929fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 930fa9e4066Sahrens * user land knows which devices are available and overall pool health. 931fa9e4066Sahrens */ 932fa9e4066Sahrens static int 933fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 934fa9e4066Sahrens { 935fa9e4066Sahrens nvlist_t *tryconfig, *config; 936fa9e4066Sahrens int error; 937fa9e4066Sahrens 938990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 939990b4856Slling &tryconfig)) != 0) 940fa9e4066Sahrens return (error); 941fa9e4066Sahrens 942fa9e4066Sahrens config = spa_tryimport(tryconfig); 943fa9e4066Sahrens 944fa9e4066Sahrens nvlist_free(tryconfig); 945fa9e4066Sahrens 946fa9e4066Sahrens if (config == NULL) 947fa9e4066Sahrens return (EINVAL); 948fa9e4066Sahrens 949e9dbad6fSeschrock error = put_nvlist(zc, config); 950fa9e4066Sahrens nvlist_free(config); 951fa9e4066Sahrens 952fa9e4066Sahrens return (error); 953fa9e4066Sahrens } 954fa9e4066Sahrens 955fa9e4066Sahrens static int 956fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc) 957fa9e4066Sahrens { 958fa9e4066Sahrens spa_t *spa; 959fa9e4066Sahrens int error; 960fa9e4066Sahrens 96106eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 96206eeb2adSek return (error); 96306eeb2adSek 964088f3894Sahrens error = spa_scrub(spa, zc->zc_cookie); 96506eeb2adSek 96606eeb2adSek spa_close(spa, FTAG); 96706eeb2adSek 968fa9e4066Sahrens return (error); 969fa9e4066Sahrens } 970fa9e4066Sahrens 971fa9e4066Sahrens static int 972fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 973fa9e4066Sahrens { 974fa9e4066Sahrens spa_t *spa; 975fa9e4066Sahrens int error; 976fa9e4066Sahrens 977fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 978fa9e4066Sahrens if (error == 0) { 979fa9e4066Sahrens spa_freeze(spa); 980fa9e4066Sahrens spa_close(spa, FTAG); 981fa9e4066Sahrens } 982fa9e4066Sahrens return (error); 983fa9e4066Sahrens } 984fa9e4066Sahrens 985eaca9bbdSeschrock static int 986eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 987eaca9bbdSeschrock { 988eaca9bbdSeschrock spa_t *spa; 989eaca9bbdSeschrock int error; 990eaca9bbdSeschrock 99106eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 99206eeb2adSek return (error); 99306eeb2adSek 994558d2d50Slling if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 995558d2d50Slling spa_close(spa, FTAG); 996558d2d50Slling return (EINVAL); 997558d2d50Slling } 998558d2d50Slling 999990b4856Slling spa_upgrade(spa, zc->zc_cookie); 100006eeb2adSek spa_close(spa, FTAG); 100106eeb2adSek 100206eeb2adSek return (error); 100306eeb2adSek } 100406eeb2adSek 100506eeb2adSek static int 100606eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 100706eeb2adSek { 100806eeb2adSek spa_t *spa; 100906eeb2adSek char *hist_buf; 101006eeb2adSek uint64_t size; 101106eeb2adSek int error; 101206eeb2adSek 101306eeb2adSek if ((size = zc->zc_history_len) == 0) 101406eeb2adSek return (EINVAL); 101506eeb2adSek 101606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 101706eeb2adSek return (error); 101806eeb2adSek 1019e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1020d7306b64Sek spa_close(spa, FTAG); 1021d7306b64Sek return (ENOTSUP); 1022d7306b64Sek } 1023d7306b64Sek 102406eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 102506eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 102606eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 1027ecd6cf80Smarks error = xcopyout(hist_buf, 1028ecd6cf80Smarks (char *)(uintptr_t)zc->zc_history, 102906eeb2adSek zc->zc_history_len); 103006eeb2adSek } 103106eeb2adSek 103206eeb2adSek spa_close(spa, FTAG); 103306eeb2adSek kmem_free(hist_buf, size); 103406eeb2adSek return (error); 103506eeb2adSek } 103606eeb2adSek 103755434c77Sek static int 103855434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 103955434c77Sek { 104055434c77Sek int error; 104155434c77Sek 1042b1b8ab34Slling if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 104355434c77Sek return (error); 104455434c77Sek 104555434c77Sek return (0); 104655434c77Sek } 104755434c77Sek 104855434c77Sek static int 104955434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 105055434c77Sek { 105155434c77Sek objset_t *osp; 105255434c77Sek int error; 105355434c77Sek 105455434c77Sek if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 1055745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &osp)) != 0) 105655434c77Sek return (error); 105755434c77Sek error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 105855434c77Sek sizeof (zc->zc_value)); 105955434c77Sek dmu_objset_close(osp); 106055434c77Sek 106155434c77Sek return (error); 106255434c77Sek } 106355434c77Sek 1064fa9e4066Sahrens static int 1065fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1066fa9e4066Sahrens { 1067fa9e4066Sahrens spa_t *spa; 1068fa9e4066Sahrens int error; 1069e7cbe64fSgw nvlist_t *config, **l2cache, **spares; 1070e7cbe64fSgw uint_t nl2cache = 0, nspares = 0; 1071fa9e4066Sahrens 1072fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1073fa9e4066Sahrens if (error != 0) 1074fa9e4066Sahrens return (error); 1075fa9e4066Sahrens 1076fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1077fa94a07fSbrendan &config); 1078fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1079fa94a07fSbrendan &l2cache, &nl2cache); 1080fa94a07fSbrendan 1081e7cbe64fSgw (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1082e7cbe64fSgw &spares, &nspares); 1083e7cbe64fSgw 1084b1b8ab34Slling /* 1085b1b8ab34Slling * A root pool with concatenated devices is not supported. 1086e7cbe64fSgw * Thus, can not add a device to a root pool. 1087e7cbe64fSgw * 1088e7cbe64fSgw * Intent log device can not be added to a rootpool because 1089e7cbe64fSgw * during mountroot, zil is replayed, a seperated log device 1090e7cbe64fSgw * can not be accessed during the mountroot time. 1091e7cbe64fSgw * 1092e7cbe64fSgw * l2cache and spare devices are ok to be added to a rootpool. 1093b1b8ab34Slling */ 1094e7cbe64fSgw if (spa->spa_bootfs != 0 && nl2cache == 0 && nspares == 0) { 1095b1b8ab34Slling spa_close(spa, FTAG); 1096b1b8ab34Slling return (EDOM); 1097b1b8ab34Slling } 1098b1b8ab34Slling 1099fa94a07fSbrendan if (error == 0) { 1100fa9e4066Sahrens error = spa_vdev_add(spa, config); 1101fa9e4066Sahrens nvlist_free(config); 1102fa9e4066Sahrens } 1103fa9e4066Sahrens spa_close(spa, FTAG); 1104fa9e4066Sahrens return (error); 1105fa9e4066Sahrens } 1106fa9e4066Sahrens 1107fa9e4066Sahrens static int 1108fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1109fa9e4066Sahrens { 111099653d4eSeschrock spa_t *spa; 111199653d4eSeschrock int error; 111299653d4eSeschrock 111399653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 111499653d4eSeschrock if (error != 0) 111599653d4eSeschrock return (error); 111699653d4eSeschrock error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 111799653d4eSeschrock spa_close(spa, FTAG); 111899653d4eSeschrock return (error); 1119fa9e4066Sahrens } 1120fa9e4066Sahrens 1121fa9e4066Sahrens static int 11223d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1123fa9e4066Sahrens { 1124fa9e4066Sahrens spa_t *spa; 1125fa9e4066Sahrens int error; 11263d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1127fa9e4066Sahrens 112806eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1129fa9e4066Sahrens return (error); 11303d7072f8Seschrock switch (zc->zc_cookie) { 11313d7072f8Seschrock case VDEV_STATE_ONLINE: 11323d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 11333d7072f8Seschrock break; 1134fa9e4066Sahrens 11353d7072f8Seschrock case VDEV_STATE_OFFLINE: 11363d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 11373d7072f8Seschrock break; 1138fa9e4066Sahrens 11393d7072f8Seschrock case VDEV_STATE_FAULTED: 11403d7072f8Seschrock error = vdev_fault(spa, zc->zc_guid); 11413d7072f8Seschrock break; 11423d7072f8Seschrock 11433d7072f8Seschrock case VDEV_STATE_DEGRADED: 11443d7072f8Seschrock error = vdev_degrade(spa, zc->zc_guid); 11453d7072f8Seschrock break; 11463d7072f8Seschrock 11473d7072f8Seschrock default: 11483d7072f8Seschrock error = EINVAL; 11493d7072f8Seschrock } 11503d7072f8Seschrock zc->zc_cookie = newstate; 1151fa9e4066Sahrens spa_close(spa, FTAG); 1152fa9e4066Sahrens return (error); 1153fa9e4066Sahrens } 1154fa9e4066Sahrens 1155fa9e4066Sahrens static int 1156fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 1157fa9e4066Sahrens { 1158fa9e4066Sahrens spa_t *spa; 1159fa9e4066Sahrens int replacing = zc->zc_cookie; 1160fa9e4066Sahrens nvlist_t *config; 1161fa9e4066Sahrens int error; 1162fa9e4066Sahrens 116306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1164fa9e4066Sahrens return (error); 1165fa9e4066Sahrens 1166990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1167990b4856Slling &config)) == 0) { 1168ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1169fa9e4066Sahrens nvlist_free(config); 1170fa9e4066Sahrens } 1171fa9e4066Sahrens 1172fa9e4066Sahrens spa_close(spa, FTAG); 1173fa9e4066Sahrens return (error); 1174fa9e4066Sahrens } 1175fa9e4066Sahrens 1176fa9e4066Sahrens static int 1177fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 1178fa9e4066Sahrens { 1179fa9e4066Sahrens spa_t *spa; 1180fa9e4066Sahrens int error; 1181fa9e4066Sahrens 118206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1183fa9e4066Sahrens return (error); 1184fa9e4066Sahrens 11858ad4d6ddSJeff Bonwick error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 1186fa9e4066Sahrens 1187fa9e4066Sahrens spa_close(spa, FTAG); 1188fa9e4066Sahrens return (error); 1189fa9e4066Sahrens } 1190fa9e4066Sahrens 1191c67d9675Seschrock static int 1192c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1193c67d9675Seschrock { 1194c67d9675Seschrock spa_t *spa; 1195e9dbad6fSeschrock char *path = zc->zc_value; 1196ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 1197c67d9675Seschrock int error; 1198c67d9675Seschrock 1199c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 1200c67d9675Seschrock if (error != 0) 1201c67d9675Seschrock return (error); 1202c67d9675Seschrock 1203c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 1204c67d9675Seschrock spa_close(spa, FTAG); 1205c67d9675Seschrock return (error); 1206c67d9675Seschrock } 1207c67d9675Seschrock 12083cb34c60Sahrens /* 12093cb34c60Sahrens * inputs: 12103cb34c60Sahrens * zc_name name of filesystem 12113cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 12123cb34c60Sahrens * 12133cb34c60Sahrens * outputs: 12143cb34c60Sahrens * zc_objset_stats stats 12153cb34c60Sahrens * zc_nvlist_dst property nvlist 12163cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 12173cb34c60Sahrens */ 1218fa9e4066Sahrens static int 1219fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc) 1220fa9e4066Sahrens { 1221fa9e4066Sahrens objset_t *os = NULL; 1222fa9e4066Sahrens int error; 12237f7322feSeschrock nvlist_t *nv; 1224fa9e4066Sahrens 1225745cd3c5Smaybee if (error = dmu_objset_open(zc->zc_name, 1226745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1227fa9e4066Sahrens return (error); 1228fa9e4066Sahrens 1229a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1230fa9e4066Sahrens 12315ad82045Snd if (zc->zc_nvlist_dst != 0 && 1232745cd3c5Smaybee (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 1233a2eea2e1Sahrens dmu_objset_stats(os, nv); 1234432f72fdSahrens /* 1235bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 1236432f72fdSahrens * which we aren't supposed to do with a 1237745cd3c5Smaybee * DS_MODE_USER hold, because it could be 1238432f72fdSahrens * inconsistent. So this is a bit of a workaround... 1239432f72fdSahrens */ 1240e7437265Sahrens if (!zc->zc_objset_stats.dds_inconsistent) { 1241e7437265Sahrens if (dmu_objset_type(os) == DMU_OST_ZVOL) 1242e7437265Sahrens VERIFY(zvol_get_stats(os, nv) == 0); 1243e7437265Sahrens } 1244e9dbad6fSeschrock error = put_nvlist(zc, nv); 12457f7322feSeschrock nvlist_free(nv); 12467f7322feSeschrock } 1247fa9e4066Sahrens 1248fa9e4066Sahrens dmu_objset_close(os); 1249fa9e4066Sahrens return (error); 1250fa9e4066Sahrens } 1251fa9e4066Sahrens 1252de8267e0Stimh static int 1253de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1254de8267e0Stimh { 1255de8267e0Stimh uint64_t value; 1256de8267e0Stimh int error; 1257de8267e0Stimh 1258de8267e0Stimh /* 1259de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 1260de8267e0Stimh * the default value (if there is one). 1261de8267e0Stimh */ 1262de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1263de8267e0Stimh return (error); 1264de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1265de8267e0Stimh return (0); 1266de8267e0Stimh } 1267de8267e0Stimh 12683cb34c60Sahrens /* 12693cb34c60Sahrens * inputs: 12703cb34c60Sahrens * zc_name name of filesystem 1271de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 12723cb34c60Sahrens * 12733cb34c60Sahrens * outputs: 1274de8267e0Stimh * zc_nvlist_dst zpl property nvlist 1275de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 12763cb34c60Sahrens */ 1277bd00f61bSrm static int 1278de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1279bd00f61bSrm { 1280de8267e0Stimh objset_t *os; 1281de8267e0Stimh int err; 1282bd00f61bSrm 1283745cd3c5Smaybee if (err = dmu_objset_open(zc->zc_name, 1284745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1285de8267e0Stimh return (err); 1286bd00f61bSrm 1287bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1288bd00f61bSrm 1289bd00f61bSrm /* 1290de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 1291745cd3c5Smaybee * which we aren't supposed to do with a DS_MODE_USER 1292745cd3c5Smaybee * hold, because it could be inconsistent. 1293bd00f61bSrm */ 1294de8267e0Stimh if (zc->zc_nvlist_dst != NULL && 1295de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 1296de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 1297de8267e0Stimh nvlist_t *nv; 1298de8267e0Stimh 1299de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1300de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1301de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1302de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1303de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1304de8267e0Stimh err = put_nvlist(zc, nv); 1305de8267e0Stimh nvlist_free(nv); 1306de8267e0Stimh } else { 1307de8267e0Stimh err = ENOENT; 1308de8267e0Stimh } 1309bd00f61bSrm dmu_objset_close(os); 1310de8267e0Stimh return (err); 1311bd00f61bSrm } 1312bd00f61bSrm 1313de8267e0Stimh /* 1314de8267e0Stimh * inputs: 1315de8267e0Stimh * zc_name name of filesystem 1316de8267e0Stimh * zc_cookie zap cursor 1317de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 1318de8267e0Stimh * 1319de8267e0Stimh * outputs: 1320de8267e0Stimh * zc_name name of next filesystem 1321de8267e0Stimh * zc_objset_stats stats 1322de8267e0Stimh * zc_nvlist_dst property nvlist 1323de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 1324de8267e0Stimh */ 1325fa9e4066Sahrens static int 1326fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1327fa9e4066Sahrens { 132887e5029aSahrens objset_t *os; 1329fa9e4066Sahrens int error; 1330fa9e4066Sahrens char *p; 1331fa9e4066Sahrens 1332745cd3c5Smaybee if (error = dmu_objset_open(zc->zc_name, 1333745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) { 133487e5029aSahrens if (error == ENOENT) 133587e5029aSahrens error = ESRCH; 133687e5029aSahrens return (error); 1337fa9e4066Sahrens } 1338fa9e4066Sahrens 1339fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 1340fa9e4066Sahrens if (p == NULL || p[1] != '\0') 1341fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1342fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 1343fa9e4066Sahrens 13445c0b6a79SRich Morris /* 13455c0b6a79SRich Morris * Pre-fetch the datasets. dmu_objset_prefetch() always returns 0 13465c0b6a79SRich Morris * but is not declared void because its called by dmu_objset_find(). 13475c0b6a79SRich Morris */ 13487f73c863SRich Morris if (zc->zc_cookie == 0) { 13497f73c863SRich Morris uint64_t cookie = 0; 13507f73c863SRich Morris int len = sizeof (zc->zc_name) - (p - zc->zc_name); 13517f73c863SRich Morris 13527f73c863SRich Morris while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) 13535c0b6a79SRich Morris (void) dmu_objset_prefetch(p, NULL); 13547f73c863SRich Morris } 13557f73c863SRich Morris 1356fa9e4066Sahrens do { 135787e5029aSahrens error = dmu_dir_list_next(os, 135887e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 135987e5029aSahrens NULL, &zc->zc_cookie); 1360fa9e4066Sahrens if (error == ENOENT) 1361fa9e4066Sahrens error = ESRCH; 136287e5029aSahrens } while (error == 0 && !INGLOBALZONE(curproc) && 1363fa9e4066Sahrens !zone_dataset_visible(zc->zc_name, NULL)); 1364745cd3c5Smaybee dmu_objset_close(os); 1365fa9e4066Sahrens 1366fa9e4066Sahrens /* 136787e5029aSahrens * If it's a hidden dataset (ie. with a '$' in its name), don't 136887e5029aSahrens * try to get stats for it. Userland will skip over it. 1369fa9e4066Sahrens */ 137087e5029aSahrens if (error == 0 && strchr(zc->zc_name, '$') == NULL) 137187e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1372fa9e4066Sahrens 1373fa9e4066Sahrens return (error); 1374fa9e4066Sahrens } 1375fa9e4066Sahrens 13763cb34c60Sahrens /* 13773cb34c60Sahrens * inputs: 13783cb34c60Sahrens * zc_name name of filesystem 13793cb34c60Sahrens * zc_cookie zap cursor 13803cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 13813cb34c60Sahrens * 13823cb34c60Sahrens * outputs: 13833cb34c60Sahrens * zc_name name of next snapshot 13843cb34c60Sahrens * zc_objset_stats stats 13853cb34c60Sahrens * zc_nvlist_dst property nvlist 13863cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 13873cb34c60Sahrens */ 1388fa9e4066Sahrens static int 1389fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1390fa9e4066Sahrens { 139187e5029aSahrens objset_t *os; 1392fa9e4066Sahrens int error; 1393fa9e4066Sahrens 1394745cd3c5Smaybee error = dmu_objset_open(zc->zc_name, 1395745cd3c5Smaybee DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os); 1396745cd3c5Smaybee if (error) 1397745cd3c5Smaybee return (error == ENOENT ? ESRCH : error); 1398fa9e4066Sahrens 13997f73c863SRich Morris if (zc->zc_cookie == 0) 14005c0b6a79SRich Morris (void) dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 14017f73c863SRich Morris NULL, DS_FIND_SNAPSHOTS); 1402b81d61a6Slling /* 1403b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 1404b81d61a6Slling * so exit immediately. 1405b81d61a6Slling */ 1406b81d61a6Slling if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 140787e5029aSahrens dmu_objset_close(os); 1408b81d61a6Slling return (ESRCH); 1409fa9e4066Sahrens } 1410fa9e4066Sahrens 141187e5029aSahrens error = dmu_snapshot_list_next(os, 141287e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 1413b38f0970Sck zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 1414745cd3c5Smaybee dmu_objset_close(os); 141587e5029aSahrens if (error == 0) 141687e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1417745cd3c5Smaybee else if (error == ENOENT) 1418745cd3c5Smaybee error = ESRCH; 1419fa9e4066Sahrens 14203cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 1421745cd3c5Smaybee if (error) 14223cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 1423fa9e4066Sahrens return (error); 1424fa9e4066Sahrens } 1425fa9e4066Sahrens 1426e7cbe64fSgw int 142791ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1428fa9e4066Sahrens { 1429e9dbad6fSeschrock nvpair_t *elem; 14305f389de5SRich Morris int error = 0; 1431e9dbad6fSeschrock uint64_t intval; 1432e9dbad6fSeschrock char *strval; 14335c0b6a79SRich Morris nvlist_t *genericnvl; 1434e9dbad6fSeschrock 1435ecd6cf80Smarks /* 1436ecd6cf80Smarks * First validate permission to set all of the properties 1437ecd6cf80Smarks */ 1438e9dbad6fSeschrock elem = NULL; 1439e9dbad6fSeschrock while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1440db870a07Sahrens const char *propname = nvpair_name(elem); 1441db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1442e9dbad6fSeschrock 1443990b4856Slling if (prop == ZPROP_INVAL) { 1444e9dbad6fSeschrock /* 1445e9dbad6fSeschrock * If this is a user-defined property, it must be a 1446e9dbad6fSeschrock * string, and there is no further validation to do. 1447e9dbad6fSeschrock */ 1448e9dbad6fSeschrock if (!zfs_prop_user(propname) || 1449e9dbad6fSeschrock nvpair_type(elem) != DATA_TYPE_STRING) 1450e9dbad6fSeschrock return (EINVAL); 1451e9dbad6fSeschrock 1452da6c28aaSamw if (error = zfs_secpolicy_write_perms(name, 1453da6c28aaSamw ZFS_DELEG_PERM_USERPROP, CRED())) 1454db870a07Sahrens return (error); 1455ecd6cf80Smarks continue; 1456e9dbad6fSeschrock } 1457fa9e4066Sahrens 145891ebeef5Sahrens if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1459db870a07Sahrens return (error); 1460db870a07Sahrens 1461e9dbad6fSeschrock /* 1462db870a07Sahrens * Check that this value is valid for this pool version 1463e9dbad6fSeschrock */ 1464e9dbad6fSeschrock switch (prop) { 1465c9431fa1Sahl case ZFS_PROP_COMPRESSION: 1466c9431fa1Sahl /* 1467c9431fa1Sahl * If the user specified gzip compression, make sure 1468c9431fa1Sahl * the SPA supports it. We ignore any errors here since 1469c9431fa1Sahl * we'll catch them later. 1470c9431fa1Sahl */ 1471c9431fa1Sahl if (nvpair_type(elem) == DATA_TYPE_UINT64 && 147215e6edf1Sgw nvpair_value_uint64(elem, &intval) == 0) { 147315e6edf1Sgw if (intval >= ZIO_COMPRESS_GZIP_1 && 147415e6edf1Sgw intval <= ZIO_COMPRESS_GZIP_9 && 14750a48a24eStimh zfs_earlier_version(name, 1476da6c28aaSamw SPA_VERSION_GZIP_COMPRESSION)) 1477da6c28aaSamw return (ENOTSUP); 147815e6edf1Sgw 147915e6edf1Sgw /* 148015e6edf1Sgw * If this is a bootable dataset then 148115e6edf1Sgw * verify that the compression algorithm 148215e6edf1Sgw * is supported for booting. We must return 148315e6edf1Sgw * something other than ENOTSUP since it 148415e6edf1Sgw * implies a downrev pool version. 148515e6edf1Sgw */ 148615e6edf1Sgw if (zfs_is_bootfs(name) && 148715e6edf1Sgw !BOOTFS_COMPRESS_VALID(intval)) 148815e6edf1Sgw return (ERANGE); 1489c9431fa1Sahl } 1490c9431fa1Sahl break; 149140feaa91Sahrens 149240feaa91Sahrens case ZFS_PROP_COPIES: 14930a48a24eStimh if (zfs_earlier_version(name, 14940a48a24eStimh SPA_VERSION_DITTO_BLOCKS)) 1495da6c28aaSamw return (ENOTSUP); 149640feaa91Sahrens break; 14979e6eda55Smarks 14989e6eda55Smarks case ZFS_PROP_SHARESMB: 1499745cd3c5Smaybee if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 15009e6eda55Smarks return (ENOTSUP); 15019e6eda55Smarks break; 1502d0f3f37eSMark Shellenbaum 1503d0f3f37eSMark Shellenbaum case ZFS_PROP_ACLINHERIT: 1504d0f3f37eSMark Shellenbaum if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1505d0f3f37eSMark Shellenbaum nvpair_value_uint64(elem, &intval) == 0) 1506d0f3f37eSMark Shellenbaum if (intval == ZFS_ACL_PASSTHROUGH_X && 1507d0f3f37eSMark Shellenbaum zfs_earlier_version(name, 1508d0f3f37eSMark Shellenbaum SPA_VERSION_PASSTHROUGH_X)) 1509d0f3f37eSMark Shellenbaum return (ENOTSUP); 151040feaa91Sahrens } 1511ecd6cf80Smarks } 1512ecd6cf80Smarks 15135c0b6a79SRich Morris VERIFY(nvlist_alloc(&genericnvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1514ecd6cf80Smarks elem = NULL; 1515ecd6cf80Smarks while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1516db870a07Sahrens const char *propname = nvpair_name(elem); 1517db870a07Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 1518ecd6cf80Smarks 1519990b4856Slling if (prop == ZPROP_INVAL) { 1520ecd6cf80Smarks VERIFY(nvpair_value_string(elem, &strval) == 0); 1521ecd6cf80Smarks error = dsl_prop_set(name, propname, 1, 1522ecd6cf80Smarks strlen(strval) + 1, strval); 1523ecd6cf80Smarks if (error == 0) 1524ecd6cf80Smarks continue; 1525ecd6cf80Smarks else 15265c0b6a79SRich Morris goto out; 1527ecd6cf80Smarks } 1528e9dbad6fSeschrock 1529e9dbad6fSeschrock switch (prop) { 1530e9dbad6fSeschrock case ZFS_PROP_QUOTA: 1531e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1532e7437265Sahrens (error = dsl_dir_set_quota(name, intval)) != 0) 15335c0b6a79SRich Morris goto out; 1534e9dbad6fSeschrock break; 1535e9dbad6fSeschrock 1536a9799022Sck case ZFS_PROP_REFQUOTA: 1537a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1538a9799022Sck (error = dsl_dataset_set_quota(name, intval)) != 0) 15395c0b6a79SRich Morris goto out; 1540a9799022Sck break; 1541a9799022Sck 1542e9dbad6fSeschrock case ZFS_PROP_RESERVATION: 1543e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1544e9dbad6fSeschrock (error = dsl_dir_set_reservation(name, 1545e9dbad6fSeschrock intval)) != 0) 15465c0b6a79SRich Morris goto out; 1547e9dbad6fSeschrock break; 1548e9dbad6fSeschrock 1549a9799022Sck case ZFS_PROP_REFRESERVATION: 1550a9799022Sck if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1551a9799022Sck (error = dsl_dataset_set_reservation(name, 1552a9799022Sck intval)) != 0) 15535c0b6a79SRich Morris goto out; 1554a9799022Sck break; 1555a9799022Sck 1556e9dbad6fSeschrock case ZFS_PROP_VOLSIZE: 1557e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 155891ebeef5Sahrens (error = zvol_set_volsize(name, 155991ebeef5Sahrens ddi_driver_major(zfs_dip), intval)) != 0) 15605c0b6a79SRich Morris goto out; 1561e9dbad6fSeschrock break; 1562e9dbad6fSeschrock 1563e9dbad6fSeschrock case ZFS_PROP_VOLBLOCKSIZE: 1564e9dbad6fSeschrock if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1565e7437265Sahrens (error = zvol_set_volblocksize(name, intval)) != 0) 15665c0b6a79SRich Morris goto out; 1567e7437265Sahrens break; 1568e7437265Sahrens 1569e7437265Sahrens case ZFS_PROP_VERSION: 1570e7437265Sahrens if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1571e7437265Sahrens (error = zfs_set_version(name, intval)) != 0) 15725c0b6a79SRich Morris goto out; 1573e9dbad6fSeschrock break; 1574e9dbad6fSeschrock 1575e9dbad6fSeschrock default: 1576e9dbad6fSeschrock if (nvpair_type(elem) == DATA_TYPE_STRING) { 1577e9dbad6fSeschrock if (zfs_prop_get_type(prop) != 15785c0b6a79SRich Morris PROP_TYPE_STRING) { 15795c0b6a79SRich Morris error = EINVAL; 15805c0b6a79SRich Morris goto out; 15815c0b6a79SRich Morris } 1582e9dbad6fSeschrock } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1583a2eea2e1Sahrens const char *unused; 1584a2eea2e1Sahrens 1585acd76fe5Seschrock VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1586e9dbad6fSeschrock 1587e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 158891ebeef5Sahrens case PROP_TYPE_NUMBER: 1589e9dbad6fSeschrock break; 159091ebeef5Sahrens case PROP_TYPE_STRING: 15915c0b6a79SRich Morris error = EINVAL; 15925c0b6a79SRich Morris goto out; 159391ebeef5Sahrens case PROP_TYPE_INDEX: 1594acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 15955c0b6a79SRich Morris intval, &unused) != 0) { 15965c0b6a79SRich Morris error = EINVAL; 15975c0b6a79SRich Morris goto out; 15985c0b6a79SRich Morris } 1599e9dbad6fSeschrock break; 1600e9dbad6fSeschrock default: 1601e7437265Sahrens cmn_err(CE_PANIC, 1602e7437265Sahrens "unknown property type"); 1603e9dbad6fSeschrock break; 1604e9dbad6fSeschrock } 1605e9dbad6fSeschrock } else { 16065c0b6a79SRich Morris error = EINVAL; 16075c0b6a79SRich Morris goto out; 1608e9dbad6fSeschrock } 16095c0b6a79SRich Morris if ((error = nvlist_add_nvpair(genericnvl, elem)) != 0) 16105c0b6a79SRich Morris goto out; 1611e9dbad6fSeschrock } 1612e9dbad6fSeschrock } 1613e9dbad6fSeschrock 16145c0b6a79SRich Morris if (nvlist_next_nvpair(genericnvl, NULL) != NULL) { 16155c0b6a79SRich Morris error = dsl_props_set(name, genericnvl); 16165c0b6a79SRich Morris } 16175c0b6a79SRich Morris out: 16185c0b6a79SRich Morris nvlist_free(genericnvl); 16195c0b6a79SRich Morris return (error); 1620fa9e4066Sahrens } 1621fa9e4066Sahrens 16223cb34c60Sahrens /* 16233cb34c60Sahrens * inputs: 16243cb34c60Sahrens * zc_name name of filesystem 16255c0b6a79SRich Morris * zc_value name of property to set 16263cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 1627bb0ade09Sahrens * zc_cookie clear existing local props? 16283cb34c60Sahrens * 16293cb34c60Sahrens * outputs: none 16303cb34c60Sahrens */ 1631fa9e4066Sahrens static int 1632e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 1633fa9e4066Sahrens { 1634e9dbad6fSeschrock nvlist_t *nvl; 1635e9dbad6fSeschrock int error; 1636e9dbad6fSeschrock 1637990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1638990b4856Slling &nvl)) != 0) 1639e9dbad6fSeschrock return (error); 1640e9dbad6fSeschrock 1641bb0ade09Sahrens if (zc->zc_cookie) { 1642bb0ade09Sahrens nvlist_t *origprops; 1643bb0ade09Sahrens objset_t *os; 1644bb0ade09Sahrens 1645bb0ade09Sahrens if (dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1646bb0ade09Sahrens DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 1647bb0ade09Sahrens if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 16486e77af0aSDavid Pacheco clear_props(zc->zc_name, origprops, nvl); 1649bb0ade09Sahrens nvlist_free(origprops); 1650bb0ade09Sahrens } 1651bb0ade09Sahrens dmu_objset_close(os); 1652bb0ade09Sahrens } 1653bb0ade09Sahrens 1654bb0ade09Sahrens } 1655bb0ade09Sahrens 165691ebeef5Sahrens error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1657ecd6cf80Smarks 1658e9dbad6fSeschrock nvlist_free(nvl); 1659e9dbad6fSeschrock return (error); 1660fa9e4066Sahrens } 1661fa9e4066Sahrens 16623cb34c60Sahrens /* 16633cb34c60Sahrens * inputs: 16643cb34c60Sahrens * zc_name name of filesystem 16653cb34c60Sahrens * zc_value name of property to inherit 16663cb34c60Sahrens * 16673cb34c60Sahrens * outputs: none 16683cb34c60Sahrens */ 1669e45ce728Sahrens static int 1670e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 1671e45ce728Sahrens { 1672e45ce728Sahrens /* the property name has been validated by zfs_secpolicy_inherit() */ 1673e45ce728Sahrens return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1674e45ce728Sahrens } 1675e45ce728Sahrens 1676b1b8ab34Slling static int 167711a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 1678b1b8ab34Slling { 1679990b4856Slling nvlist_t *props; 1680b1b8ab34Slling spa_t *spa; 1681990b4856Slling int error; 1682379c004dSEric Schrock nvpair_t *elem; 1683b1b8ab34Slling 1684990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1685990b4856Slling &props))) 1686b1b8ab34Slling return (error); 1687b1b8ab34Slling 1688379c004dSEric Schrock /* 1689379c004dSEric Schrock * If the only property is the configfile, then just do a spa_lookup() 1690379c004dSEric Schrock * to handle the faulted case. 1691379c004dSEric Schrock */ 1692379c004dSEric Schrock elem = nvlist_next_nvpair(props, NULL); 1693379c004dSEric Schrock if (elem != NULL && strcmp(nvpair_name(elem), 1694379c004dSEric Schrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 1695379c004dSEric Schrock nvlist_next_nvpair(props, elem) == NULL) { 1696379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 1697379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) { 1698379c004dSEric Schrock spa_configfile_set(spa, props, B_FALSE); 1699379c004dSEric Schrock spa_config_sync(spa, B_FALSE, B_TRUE); 1700379c004dSEric Schrock } 1701379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 1702379c004dSEric Schrock if (spa != NULL) 1703379c004dSEric Schrock return (0); 1704379c004dSEric Schrock } 1705379c004dSEric Schrock 1706b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1707990b4856Slling nvlist_free(props); 1708b1b8ab34Slling return (error); 1709b1b8ab34Slling } 1710b1b8ab34Slling 1711990b4856Slling error = spa_prop_set(spa, props); 1712b1b8ab34Slling 1713990b4856Slling nvlist_free(props); 1714b1b8ab34Slling spa_close(spa, FTAG); 1715b1b8ab34Slling 1716b1b8ab34Slling return (error); 1717b1b8ab34Slling } 1718b1b8ab34Slling 1719b1b8ab34Slling static int 172011a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 1721b1b8ab34Slling { 1722b1b8ab34Slling spa_t *spa; 1723b1b8ab34Slling int error; 1724b1b8ab34Slling nvlist_t *nvp = NULL; 1725b1b8ab34Slling 1726379c004dSEric Schrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1727379c004dSEric Schrock /* 1728379c004dSEric Schrock * If the pool is faulted, there may be properties we can still 1729379c004dSEric Schrock * get (such as altroot and cachefile), so attempt to get them 1730379c004dSEric Schrock * anyway. 1731379c004dSEric Schrock */ 1732379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 1733379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) 1734379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 1735379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 1736379c004dSEric Schrock } else { 1737379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 1738379c004dSEric Schrock spa_close(spa, FTAG); 1739379c004dSEric Schrock } 1740b1b8ab34Slling 1741b1b8ab34Slling if (error == 0 && zc->zc_nvlist_dst != NULL) 1742b1b8ab34Slling error = put_nvlist(zc, nvp); 1743b1b8ab34Slling else 1744b1b8ab34Slling error = EFAULT; 1745b1b8ab34Slling 1746379c004dSEric Schrock nvlist_free(nvp); 1747b1b8ab34Slling return (error); 1748b1b8ab34Slling } 1749b1b8ab34Slling 1750ecd6cf80Smarks static int 1751ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1752ecd6cf80Smarks { 1753ecd6cf80Smarks nvlist_t *nvp; 1754ecd6cf80Smarks int error; 1755ecd6cf80Smarks uint32_t uid; 1756ecd6cf80Smarks uint32_t gid; 1757ecd6cf80Smarks uint32_t *groups; 1758ecd6cf80Smarks uint_t group_cnt; 1759ecd6cf80Smarks cred_t *usercred; 1760ecd6cf80Smarks 1761990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1762990b4856Slling &nvp)) != 0) { 1763ecd6cf80Smarks return (error); 1764ecd6cf80Smarks } 1765ecd6cf80Smarks 1766ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1767ecd6cf80Smarks ZFS_DELEG_PERM_UID, &uid)) != 0) { 1768ecd6cf80Smarks nvlist_free(nvp); 1769ecd6cf80Smarks return (EPERM); 1770ecd6cf80Smarks } 1771ecd6cf80Smarks 1772ecd6cf80Smarks if ((error = nvlist_lookup_uint32(nvp, 1773ecd6cf80Smarks ZFS_DELEG_PERM_GID, &gid)) != 0) { 1774ecd6cf80Smarks nvlist_free(nvp); 1775ecd6cf80Smarks return (EPERM); 1776ecd6cf80Smarks } 1777ecd6cf80Smarks 1778ecd6cf80Smarks if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1779ecd6cf80Smarks &groups, &group_cnt)) != 0) { 1780ecd6cf80Smarks nvlist_free(nvp); 1781ecd6cf80Smarks return (EPERM); 1782ecd6cf80Smarks } 1783ecd6cf80Smarks usercred = cralloc(); 1784ecd6cf80Smarks if ((crsetugid(usercred, uid, gid) != 0) || 1785ecd6cf80Smarks (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1786ecd6cf80Smarks nvlist_free(nvp); 1787ecd6cf80Smarks crfree(usercred); 1788ecd6cf80Smarks return (EPERM); 1789ecd6cf80Smarks } 1790ecd6cf80Smarks nvlist_free(nvp); 1791ecd6cf80Smarks error = dsl_deleg_access(zc->zc_name, 179291ebeef5Sahrens zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 1793ecd6cf80Smarks crfree(usercred); 1794ecd6cf80Smarks return (error); 1795ecd6cf80Smarks } 1796ecd6cf80Smarks 17973cb34c60Sahrens /* 17983cb34c60Sahrens * inputs: 17993cb34c60Sahrens * zc_name name of filesystem 18003cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 18013cb34c60Sahrens * zc_perm_action allow/unallow flag 18023cb34c60Sahrens * 18033cb34c60Sahrens * outputs: none 18043cb34c60Sahrens */ 1805ecd6cf80Smarks static int 1806ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 1807ecd6cf80Smarks { 1808ecd6cf80Smarks int error; 1809ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 1810ecd6cf80Smarks 1811990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1812990b4856Slling &fsaclnv)) != 0) 1813ecd6cf80Smarks return (error); 1814ecd6cf80Smarks 1815ecd6cf80Smarks /* 1816ecd6cf80Smarks * Verify nvlist is constructed correctly 1817ecd6cf80Smarks */ 1818ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1819ecd6cf80Smarks nvlist_free(fsaclnv); 1820ecd6cf80Smarks return (EINVAL); 1821ecd6cf80Smarks } 1822ecd6cf80Smarks 1823ecd6cf80Smarks /* 1824ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 1825ecd6cf80Smarks * that user is allowed to hand out each permission in 1826ecd6cf80Smarks * the nvlist(s) 1827ecd6cf80Smarks */ 1828ecd6cf80Smarks 182991ebeef5Sahrens error = secpolicy_zfs(CRED()); 1830ecd6cf80Smarks if (error) { 183191ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 183291ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 183391ebeef5Sahrens fsaclnv, CRED()); 183491ebeef5Sahrens } else { 183591ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 183691ebeef5Sahrens fsaclnv, CRED()); 183791ebeef5Sahrens } 1838ecd6cf80Smarks } 1839ecd6cf80Smarks 1840ecd6cf80Smarks if (error == 0) 1841ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1842ecd6cf80Smarks 1843ecd6cf80Smarks nvlist_free(fsaclnv); 1844ecd6cf80Smarks return (error); 1845ecd6cf80Smarks } 1846ecd6cf80Smarks 18473cb34c60Sahrens /* 18483cb34c60Sahrens * inputs: 18493cb34c60Sahrens * zc_name name of filesystem 18503cb34c60Sahrens * 18513cb34c60Sahrens * outputs: 18523cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 18533cb34c60Sahrens */ 1854ecd6cf80Smarks static int 1855ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 1856ecd6cf80Smarks { 1857ecd6cf80Smarks nvlist_t *nvp; 1858ecd6cf80Smarks int error; 1859ecd6cf80Smarks 1860ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1861ecd6cf80Smarks error = put_nvlist(zc, nvp); 1862ecd6cf80Smarks nvlist_free(nvp); 1863ecd6cf80Smarks } 1864ecd6cf80Smarks 1865ecd6cf80Smarks return (error); 1866ecd6cf80Smarks } 1867ecd6cf80Smarks 18683cb34c60Sahrens /* 18693cb34c60Sahrens * inputs: 18703cb34c60Sahrens * zc_name name of volume 18713cb34c60Sahrens * 18723cb34c60Sahrens * outputs: none 18733cb34c60Sahrens */ 1874fa9e4066Sahrens static int 1875fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc) 1876fa9e4066Sahrens { 187791ebeef5Sahrens return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1878fa9e4066Sahrens } 1879fa9e4066Sahrens 18803cb34c60Sahrens /* 18813cb34c60Sahrens * inputs: 18823cb34c60Sahrens * zc_name name of volume 18833cb34c60Sahrens * 18843cb34c60Sahrens * outputs: none 18853cb34c60Sahrens */ 1886fa9e4066Sahrens static int 1887fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc) 1888fa9e4066Sahrens { 1889e9dbad6fSeschrock return (zvol_remove_minor(zc->zc_name)); 1890fa9e4066Sahrens } 1891fa9e4066Sahrens 1892fa9e4066Sahrens /* 1893fa9e4066Sahrens * Search the vfs list for a specified resource. Returns a pointer to it 1894fa9e4066Sahrens * or NULL if no suitable entry is found. The caller of this routine 1895fa9e4066Sahrens * is responsible for releasing the returned vfs pointer. 1896fa9e4066Sahrens */ 1897fa9e4066Sahrens static vfs_t * 1898fa9e4066Sahrens zfs_get_vfs(const char *resource) 1899fa9e4066Sahrens { 1900fa9e4066Sahrens struct vfs *vfsp; 1901fa9e4066Sahrens struct vfs *vfs_found = NULL; 1902fa9e4066Sahrens 1903fa9e4066Sahrens vfs_list_read_lock(); 1904fa9e4066Sahrens vfsp = rootvfs; 1905fa9e4066Sahrens do { 1906fa9e4066Sahrens if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1907fa9e4066Sahrens VFS_HOLD(vfsp); 1908fa9e4066Sahrens vfs_found = vfsp; 1909fa9e4066Sahrens break; 1910fa9e4066Sahrens } 1911fa9e4066Sahrens vfsp = vfsp->vfs_next; 1912fa9e4066Sahrens } while (vfsp != rootvfs); 1913fa9e4066Sahrens vfs_list_unlock(); 1914fa9e4066Sahrens return (vfs_found); 1915fa9e4066Sahrens } 1916fa9e4066Sahrens 1917ecd6cf80Smarks /* ARGSUSED */ 1918fa9e4066Sahrens static void 1919ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1920fa9e4066Sahrens { 1921da6c28aaSamw zfs_creat_t *zct = arg; 1922da6c28aaSamw 1923de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 1924da6c28aaSamw } 1925da6c28aaSamw 1926de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 1927da6c28aaSamw 1928da6c28aaSamw /* 1929de8267e0Stimh * inputs: 19300a48a24eStimh * createprops list of properties requested by creator 19310a48a24eStimh * default_zplver zpl version to use if unspecified in createprops 19320a48a24eStimh * fuids_ok fuids allowed in this version of the spa? 19330a48a24eStimh * os parent objset pointer (NULL if root fs) 1934de8267e0Stimh * 1935de8267e0Stimh * outputs: 1936de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 19370a48a24eStimh * is_ci true if requested file system will be purely case-insensitive 1938da6c28aaSamw * 1939de8267e0Stimh * Determine the settings for utf8only, normalization and 1940de8267e0Stimh * casesensitivity. Specific values may have been requested by the 1941de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 1942de8267e0Stimh * the file system is of too early a vintage, a creator can not 1943de8267e0Stimh * request settings for these properties, even if the requested 1944de8267e0Stimh * setting is the default value. We don't actually want to create dsl 1945de8267e0Stimh * properties for these, so remove them from the source nvlist after 1946de8267e0Stimh * processing. 1947da6c28aaSamw */ 1948da6c28aaSamw static int 19490a48a24eStimh zfs_fill_zplprops_impl(objset_t *os, uint64_t default_zplver, 19500a48a24eStimh boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 19510a48a24eStimh boolean_t *is_ci) 1952da6c28aaSamw { 19530a48a24eStimh uint64_t zplver = default_zplver; 1954de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 1955de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 1956de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 1957da6c28aaSamw 1958de8267e0Stimh ASSERT(zplprops != NULL); 1959da6c28aaSamw 1960de8267e0Stimh /* 1961de8267e0Stimh * Pull out creator prop choices, if any. 1962de8267e0Stimh */ 1963de8267e0Stimh if (createprops) { 19640a48a24eStimh (void) nvlist_lookup_uint64(createprops, 19650a48a24eStimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 1966de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1967de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 1968de8267e0Stimh (void) nvlist_remove_all(createprops, 1969de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 1970de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1971de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 1972de8267e0Stimh (void) nvlist_remove_all(createprops, 1973de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1974de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 1975de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 1976de8267e0Stimh (void) nvlist_remove_all(createprops, 1977de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 1978de8267e0Stimh } 1979da6c28aaSamw 1980c2a93d44Stimh /* 19810a48a24eStimh * If the zpl version requested is whacky or the file system 19820a48a24eStimh * or pool is version is too "young" to support normalization 19830a48a24eStimh * and the creator tried to set a value for one of the props, 19840a48a24eStimh * error out. 1985c2a93d44Stimh */ 19860a48a24eStimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 19870a48a24eStimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 19880a48a24eStimh (zplver < ZPL_VERSION_NORMALIZATION && 1989de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 19900a48a24eStimh sense != ZFS_PROP_UNDEFINED))) 1991de8267e0Stimh return (ENOTSUP); 1992c2a93d44Stimh 1993de8267e0Stimh /* 1994de8267e0Stimh * Put the version in the zplprops 1995de8267e0Stimh */ 1996de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 1997de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 1998da6c28aaSamw 1999de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 2000de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 2001de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2002de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 2003da6c28aaSamw 2004c2a93d44Stimh /* 2005de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 2006c2a93d44Stimh */ 2007de8267e0Stimh if (norm) 2008de8267e0Stimh u8 = 1; 2009de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 2010de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 2011de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2012de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 2013de8267e0Stimh 2014de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 2015de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 2016de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 2017de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 2018c2a93d44Stimh 2019ab04eb8eStimh if (is_ci) 2020ab04eb8eStimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 2021ab04eb8eStimh 2022da6c28aaSamw return (0); 2023fa9e4066Sahrens } 2024fa9e4066Sahrens 20250a48a24eStimh static int 20260a48a24eStimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 20270a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 20280a48a24eStimh { 20290a48a24eStimh boolean_t fuids_ok = B_TRUE; 20300a48a24eStimh uint64_t zplver = ZPL_VERSION; 20310a48a24eStimh objset_t *os = NULL; 20320a48a24eStimh char parentname[MAXNAMELEN]; 20330a48a24eStimh char *cp; 20340a48a24eStimh int error; 20350a48a24eStimh 20360a48a24eStimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 20370a48a24eStimh cp = strrchr(parentname, '/'); 20380a48a24eStimh ASSERT(cp != NULL); 20390a48a24eStimh cp[0] = '\0'; 20400a48a24eStimh 20410a48a24eStimh if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 20420a48a24eStimh zplver = ZPL_VERSION_FUID - 1; 20430a48a24eStimh fuids_ok = B_FALSE; 20440a48a24eStimh } 20450a48a24eStimh 20460a48a24eStimh /* 20470a48a24eStimh * Open parent object set so we can inherit zplprop values. 20480a48a24eStimh */ 20490a48a24eStimh if ((error = dmu_objset_open(parentname, DMU_OST_ANY, 20500a48a24eStimh DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) 20510a48a24eStimh return (error); 20520a48a24eStimh 20530a48a24eStimh error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 20540a48a24eStimh zplprops, is_ci); 20550a48a24eStimh dmu_objset_close(os); 20560a48a24eStimh return (error); 20570a48a24eStimh } 20580a48a24eStimh 20590a48a24eStimh static int 20600a48a24eStimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 20610a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 20620a48a24eStimh { 20630a48a24eStimh boolean_t fuids_ok = B_TRUE; 20640a48a24eStimh uint64_t zplver = ZPL_VERSION; 20650a48a24eStimh int error; 20660a48a24eStimh 20670a48a24eStimh if (spa_vers < SPA_VERSION_FUID) { 20680a48a24eStimh zplver = ZPL_VERSION_FUID - 1; 20690a48a24eStimh fuids_ok = B_FALSE; 20700a48a24eStimh } 20710a48a24eStimh 20720a48a24eStimh error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 20730a48a24eStimh zplprops, is_ci); 20740a48a24eStimh return (error); 20750a48a24eStimh } 20760a48a24eStimh 20773cb34c60Sahrens /* 20783cb34c60Sahrens * inputs: 20793cb34c60Sahrens * zc_objset_type type of objset to create (fs vs zvol) 20803cb34c60Sahrens * zc_name name of new objset 20813cb34c60Sahrens * zc_value name of snapshot to clone from (may be empty) 20823cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 20833cb34c60Sahrens * 2084de8267e0Stimh * outputs: none 20853cb34c60Sahrens */ 2086fa9e4066Sahrens static int 2087fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc) 2088fa9e4066Sahrens { 2089fa9e4066Sahrens objset_t *clone; 2090fa9e4066Sahrens int error = 0; 2091da6c28aaSamw zfs_creat_t zct; 2092ecd6cf80Smarks nvlist_t *nvprops = NULL; 2093ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2094fa9e4066Sahrens dmu_objset_type_t type = zc->zc_objset_type; 2095fa9e4066Sahrens 2096fa9e4066Sahrens switch (type) { 2097fa9e4066Sahrens 2098fa9e4066Sahrens case DMU_OST_ZFS: 2099fa9e4066Sahrens cbfunc = zfs_create_cb; 2100fa9e4066Sahrens break; 2101fa9e4066Sahrens 2102fa9e4066Sahrens case DMU_OST_ZVOL: 2103fa9e4066Sahrens cbfunc = zvol_create_cb; 2104fa9e4066Sahrens break; 2105fa9e4066Sahrens 2106fa9e4066Sahrens default: 21071d452cf5Sahrens cbfunc = NULL; 2108e7cbe64fSgw break; 2109fa9e4066Sahrens } 2110f18faf3fSek if (strchr(zc->zc_name, '@') || 2111f18faf3fSek strchr(zc->zc_name, '%')) 21121d452cf5Sahrens return (EINVAL); 2113fa9e4066Sahrens 2114e9dbad6fSeschrock if (zc->zc_nvlist_src != NULL && 2115990b4856Slling (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2116990b4856Slling &nvprops)) != 0) 2117e9dbad6fSeschrock return (error); 2118e9dbad6fSeschrock 2119de8267e0Stimh zct.zct_zplprops = NULL; 2120da6c28aaSamw zct.zct_props = nvprops; 2121da6c28aaSamw 2122e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 2123fa9e4066Sahrens /* 2124fa9e4066Sahrens * We're creating a clone of an existing snapshot. 2125fa9e4066Sahrens */ 2126e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2127e9dbad6fSeschrock if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 2128ecd6cf80Smarks nvlist_free(nvprops); 2129fa9e4066Sahrens return (EINVAL); 2130e9dbad6fSeschrock } 2131fa9e4066Sahrens 2132e9dbad6fSeschrock error = dmu_objset_open(zc->zc_value, type, 2133745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &clone); 2134e9dbad6fSeschrock if (error) { 2135ecd6cf80Smarks nvlist_free(nvprops); 2136fa9e4066Sahrens return (error); 2137e9dbad6fSeschrock } 2138ab04eb8eStimh 2139ab04eb8eStimh error = dmu_objset_create(zc->zc_name, type, clone, 0, 2140ab04eb8eStimh NULL, NULL); 2141da6c28aaSamw if (error) { 2142da6c28aaSamw dmu_objset_close(clone); 2143da6c28aaSamw nvlist_free(nvprops); 2144da6c28aaSamw return (error); 2145da6c28aaSamw } 2146fa9e4066Sahrens dmu_objset_close(clone); 2147fa9e4066Sahrens } else { 2148ab04eb8eStimh boolean_t is_insensitive = B_FALSE; 2149ab04eb8eStimh 2150e9dbad6fSeschrock if (cbfunc == NULL) { 2151ecd6cf80Smarks nvlist_free(nvprops); 21521d452cf5Sahrens return (EINVAL); 2153e9dbad6fSeschrock } 21545c5460e9Seschrock 2155e9dbad6fSeschrock if (type == DMU_OST_ZVOL) { 2156e9dbad6fSeschrock uint64_t volsize, volblocksize; 2157e9dbad6fSeschrock 2158ecd6cf80Smarks if (nvprops == NULL || 2159ecd6cf80Smarks nvlist_lookup_uint64(nvprops, 2160e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 2161e9dbad6fSeschrock &volsize) != 0) { 2162ecd6cf80Smarks nvlist_free(nvprops); 2163e9dbad6fSeschrock return (EINVAL); 2164e9dbad6fSeschrock } 2165e9dbad6fSeschrock 2166ecd6cf80Smarks if ((error = nvlist_lookup_uint64(nvprops, 2167e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2168e9dbad6fSeschrock &volblocksize)) != 0 && error != ENOENT) { 2169ecd6cf80Smarks nvlist_free(nvprops); 2170e9dbad6fSeschrock return (EINVAL); 2171e9dbad6fSeschrock } 2172e9dbad6fSeschrock 2173e9dbad6fSeschrock if (error != 0) 2174e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric( 2175e9dbad6fSeschrock ZFS_PROP_VOLBLOCKSIZE); 2176e9dbad6fSeschrock 2177e9dbad6fSeschrock if ((error = zvol_check_volblocksize( 2178e9dbad6fSeschrock volblocksize)) != 0 || 2179e9dbad6fSeschrock (error = zvol_check_volsize(volsize, 2180e9dbad6fSeschrock volblocksize)) != 0) { 2181ecd6cf80Smarks nvlist_free(nvprops); 21825c5460e9Seschrock return (error); 2183e9dbad6fSeschrock } 2184e7437265Sahrens } else if (type == DMU_OST_ZFS) { 2185da6c28aaSamw int error; 2186da6c28aaSamw 2187da6c28aaSamw /* 2188da6c28aaSamw * We have to have normalization and 2189da6c28aaSamw * case-folding flags correct when we do the 2190da6c28aaSamw * file system creation, so go figure them out 2191de8267e0Stimh * now. 2192da6c28aaSamw */ 2193de8267e0Stimh VERIFY(nvlist_alloc(&zct.zct_zplprops, 2194de8267e0Stimh NV_UNIQUE_NAME, KM_SLEEP) == 0); 2195de8267e0Stimh error = zfs_fill_zplprops(zc->zc_name, nvprops, 21960a48a24eStimh zct.zct_zplprops, &is_insensitive); 2197da6c28aaSamw if (error != 0) { 2198da6c28aaSamw nvlist_free(nvprops); 2199de8267e0Stimh nvlist_free(zct.zct_zplprops); 2200da6c28aaSamw return (error); 2201da6c28aaSamw } 2202da6c28aaSamw } 2203ab04eb8eStimh error = dmu_objset_create(zc->zc_name, type, NULL, 2204ab04eb8eStimh is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 2205de8267e0Stimh nvlist_free(zct.zct_zplprops); 2206fa9e4066Sahrens } 2207e9dbad6fSeschrock 2208e9dbad6fSeschrock /* 2209e9dbad6fSeschrock * It would be nice to do this atomically. 2210e9dbad6fSeschrock */ 2211e9dbad6fSeschrock if (error == 0) { 221291ebeef5Sahrens if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 2213e9dbad6fSeschrock (void) dmu_objset_destroy(zc->zc_name); 2214e9dbad6fSeschrock } 2215ecd6cf80Smarks nvlist_free(nvprops); 2216fa9e4066Sahrens return (error); 2217fa9e4066Sahrens } 2218fa9e4066Sahrens 2219bb0ade09Sahrens struct snap_prop_arg { 2220bb0ade09Sahrens nvlist_t *nvprops; 2221bb0ade09Sahrens const char *snapname; 2222bb0ade09Sahrens }; 2223bb0ade09Sahrens 2224bb0ade09Sahrens static int 2225bb0ade09Sahrens set_snap_props(char *name, void *arg) 2226bb0ade09Sahrens { 2227bb0ade09Sahrens struct snap_prop_arg *snpa = arg; 2228bb0ade09Sahrens int len = strlen(name) + strlen(snpa->snapname) + 2; 2229bb0ade09Sahrens char *buf = kmem_alloc(len, KM_SLEEP); 2230bb0ade09Sahrens int err; 2231bb0ade09Sahrens 2232bb0ade09Sahrens (void) snprintf(buf, len, "%s@%s", name, snpa->snapname); 2233bb0ade09Sahrens err = zfs_set_prop_nvlist(buf, snpa->nvprops); 2234bb0ade09Sahrens if (err) 2235bb0ade09Sahrens (void) dmu_objset_destroy(buf); 2236bb0ade09Sahrens kmem_free(buf, len); 2237bb0ade09Sahrens return (err); 2238bb0ade09Sahrens } 2239bb0ade09Sahrens 22403cb34c60Sahrens /* 22413cb34c60Sahrens * inputs: 22423cb34c60Sahrens * zc_name name of filesystem 22433cb34c60Sahrens * zc_value short name of snapshot 22443cb34c60Sahrens * zc_cookie recursive flag 22453cb34c60Sahrens * 22463cb34c60Sahrens * outputs: none 22473cb34c60Sahrens */ 2248fa9e4066Sahrens static int 22491d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc) 2250fa9e4066Sahrens { 2251bb0ade09Sahrens nvlist_t *nvprops = NULL; 2252bb0ade09Sahrens int error; 2253bb0ade09Sahrens boolean_t recursive = zc->zc_cookie; 2254bb0ade09Sahrens 2255e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 22561d452cf5Sahrens return (EINVAL); 2257bb0ade09Sahrens 2258bb0ade09Sahrens if (zc->zc_nvlist_src != NULL && 2259bb0ade09Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2260bb0ade09Sahrens &nvprops)) != 0) 2261bb0ade09Sahrens return (error); 2262bb0ade09Sahrens 2263bb0ade09Sahrens error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, recursive); 2264bb0ade09Sahrens 2265bb0ade09Sahrens /* 2266bb0ade09Sahrens * It would be nice to do this atomically. 2267bb0ade09Sahrens */ 2268bb0ade09Sahrens if (error == 0) { 2269bb0ade09Sahrens struct snap_prop_arg snpa; 2270bb0ade09Sahrens snpa.nvprops = nvprops; 2271bb0ade09Sahrens snpa.snapname = zc->zc_value; 2272bb0ade09Sahrens if (recursive) { 2273bb0ade09Sahrens error = dmu_objset_find(zc->zc_name, 2274bb0ade09Sahrens set_snap_props, &snpa, DS_FIND_CHILDREN); 2275bb0ade09Sahrens if (error) { 2276bb0ade09Sahrens (void) dmu_snapshots_destroy(zc->zc_name, 2277bb0ade09Sahrens zc->zc_value); 2278bb0ade09Sahrens } 2279bb0ade09Sahrens } else { 2280bb0ade09Sahrens error = set_snap_props(zc->zc_name, &snpa); 2281bb0ade09Sahrens } 2282bb0ade09Sahrens } 2283bb0ade09Sahrens nvlist_free(nvprops); 2284bb0ade09Sahrens return (error); 22851d452cf5Sahrens } 2286fa9e4066Sahrens 2287cdf5b4caSmmusante int 22881d452cf5Sahrens zfs_unmount_snap(char *name, void *arg) 22891d452cf5Sahrens { 22900b69c2f0Sahrens vfs_t *vfsp = NULL; 22911d452cf5Sahrens 2292745cd3c5Smaybee if (arg) { 2293745cd3c5Smaybee char *snapname = arg; 2294745cd3c5Smaybee int len = strlen(name) + strlen(snapname) + 2; 2295745cd3c5Smaybee char *buf = kmem_alloc(len, KM_SLEEP); 22961d452cf5Sahrens 2297745cd3c5Smaybee (void) strcpy(buf, name); 2298745cd3c5Smaybee (void) strcat(buf, "@"); 2299745cd3c5Smaybee (void) strcat(buf, snapname); 2300745cd3c5Smaybee vfsp = zfs_get_vfs(buf); 2301745cd3c5Smaybee kmem_free(buf, len); 23020b69c2f0Sahrens } else if (strchr(name, '@')) { 23031d452cf5Sahrens vfsp = zfs_get_vfs(name); 23041d452cf5Sahrens } 23051d452cf5Sahrens 23061d452cf5Sahrens if (vfsp) { 2307fa9e4066Sahrens /* 23081d452cf5Sahrens * Always force the unmount for snapshots. 2309fa9e4066Sahrens */ 23101d452cf5Sahrens int flag = MS_FORCE; 23111d452cf5Sahrens int err; 23121d452cf5Sahrens 23131d452cf5Sahrens if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 2314fa9e4066Sahrens VFS_RELE(vfsp); 23151d452cf5Sahrens return (err); 2316fa9e4066Sahrens } 23171d452cf5Sahrens VFS_RELE(vfsp); 23181d452cf5Sahrens if ((err = dounmount(vfsp, flag, kcred)) != 0) 23191d452cf5Sahrens return (err); 23201d452cf5Sahrens } 23211d452cf5Sahrens return (0); 23221d452cf5Sahrens } 23231d452cf5Sahrens 23243cb34c60Sahrens /* 23253cb34c60Sahrens * inputs: 23263cb34c60Sahrens * zc_name name of filesystem 23273cb34c60Sahrens * zc_value short name of snapshot 23283cb34c60Sahrens * 23293cb34c60Sahrens * outputs: none 23303cb34c60Sahrens */ 23311d452cf5Sahrens static int 23321d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc) 23331d452cf5Sahrens { 23341d452cf5Sahrens int err; 23351d452cf5Sahrens 2336e9dbad6fSeschrock if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 23371d452cf5Sahrens return (EINVAL); 23381d452cf5Sahrens err = dmu_objset_find(zc->zc_name, 2339e9dbad6fSeschrock zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 23401d452cf5Sahrens if (err) 23411d452cf5Sahrens return (err); 2342e9dbad6fSeschrock return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 23431d452cf5Sahrens } 23441d452cf5Sahrens 23453cb34c60Sahrens /* 23463cb34c60Sahrens * inputs: 23473cb34c60Sahrens * zc_name name of dataset to destroy 23483cb34c60Sahrens * zc_objset_type type of objset 23493cb34c60Sahrens * 23503cb34c60Sahrens * outputs: none 23513cb34c60Sahrens */ 23521d452cf5Sahrens static int 23531d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 23541d452cf5Sahrens { 23551d452cf5Sahrens if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 23561d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 23571d452cf5Sahrens if (err) 23581d452cf5Sahrens return (err); 2359fa9e4066Sahrens } 2360fa9e4066Sahrens 2361fa9e4066Sahrens return (dmu_objset_destroy(zc->zc_name)); 2362fa9e4066Sahrens } 2363fa9e4066Sahrens 23643cb34c60Sahrens /* 23653cb34c60Sahrens * inputs: 23664ccbb6e7Sahrens * zc_name name of dataset to rollback (to most recent snapshot) 23673cb34c60Sahrens * 23683cb34c60Sahrens * outputs: none 23693cb34c60Sahrens */ 2370fa9e4066Sahrens static int 2371fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc) 2372fa9e4066Sahrens { 23734ccbb6e7Sahrens objset_t *os; 23744ccbb6e7Sahrens int error; 23754ccbb6e7Sahrens zfsvfs_t *zfsvfs = NULL; 23764ccbb6e7Sahrens 23774ccbb6e7Sahrens /* 23784ccbb6e7Sahrens * Get the zfsvfs for the receiving objset. There 23794ccbb6e7Sahrens * won't be one if we're operating on a zvol, if the 23804ccbb6e7Sahrens * objset doesn't exist yet, or is not mounted. 23814ccbb6e7Sahrens */ 2382745cd3c5Smaybee error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, DS_MODE_USER, &os); 23834ccbb6e7Sahrens if (error) 23844ccbb6e7Sahrens return (error); 23854ccbb6e7Sahrens 23864ccbb6e7Sahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 23874ccbb6e7Sahrens mutex_enter(&os->os->os_user_ptr_lock); 23884ccbb6e7Sahrens zfsvfs = dmu_objset_get_user(os); 23894ccbb6e7Sahrens if (zfsvfs != NULL) 23904ccbb6e7Sahrens VFS_HOLD(zfsvfs->z_vfs); 23914ccbb6e7Sahrens mutex_exit(&os->os->os_user_ptr_lock); 23924ccbb6e7Sahrens } 23934ccbb6e7Sahrens 23944ccbb6e7Sahrens if (zfsvfs != NULL) { 23956a0f0066SEric Taylor char *osname; 23964ccbb6e7Sahrens int mode; 23974ccbb6e7Sahrens 23986a0f0066SEric Taylor osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 239947f263f4Sek error = zfs_suspend_fs(zfsvfs, osname, &mode); 240047f263f4Sek if (error == 0) { 240147f263f4Sek int resume_err; 24024ccbb6e7Sahrens 240347f263f4Sek ASSERT(strcmp(osname, zc->zc_name) == 0); 240447f263f4Sek error = dmu_objset_rollback(os); 240547f263f4Sek resume_err = zfs_resume_fs(zfsvfs, osname, mode); 240647f263f4Sek error = error ? error : resume_err; 240747f263f4Sek } else { 240847f263f4Sek dmu_objset_close(os); 240947f263f4Sek } 24106a0f0066SEric Taylor kmem_free(osname, MAXNAMELEN); 24114ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 24124ccbb6e7Sahrens } else { 24134ccbb6e7Sahrens error = dmu_objset_rollback(os); 24144ccbb6e7Sahrens } 2415745cd3c5Smaybee /* Note, the dmu_objset_rollback() releases the objset for us. */ 24164ccbb6e7Sahrens 24174ccbb6e7Sahrens return (error); 2418fa9e4066Sahrens } 2419fa9e4066Sahrens 24203cb34c60Sahrens /* 24213cb34c60Sahrens * inputs: 24223cb34c60Sahrens * zc_name old name of dataset 24233cb34c60Sahrens * zc_value new name of dataset 24243cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 24253cb34c60Sahrens * 24263cb34c60Sahrens * outputs: none 24273cb34c60Sahrens */ 2428fa9e4066Sahrens static int 2429fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 2430fa9e4066Sahrens { 24317f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 2432cdf5b4caSmmusante 2433e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2434f18faf3fSek if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2435f18faf3fSek strchr(zc->zc_value, '%')) 2436fa9e4066Sahrens return (EINVAL); 2437fa9e4066Sahrens 2438cdf5b4caSmmusante /* 2439cdf5b4caSmmusante * Unmount snapshot unless we're doing a recursive rename, 2440cdf5b4caSmmusante * in which case the dataset code figures out which snapshots 2441cdf5b4caSmmusante * to unmount. 2442cdf5b4caSmmusante */ 2443cdf5b4caSmmusante if (!recursive && strchr(zc->zc_name, '@') != NULL && 2444fa9e4066Sahrens zc->zc_objset_type == DMU_OST_ZFS) { 24451d452cf5Sahrens int err = zfs_unmount_snap(zc->zc_name, NULL); 24461d452cf5Sahrens if (err) 24471d452cf5Sahrens return (err); 2448fa9e4066Sahrens } 2449cdf5b4caSmmusante return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2450fa9e4066Sahrens } 2451fa9e4066Sahrens 2452745cd3c5Smaybee static void 24536e77af0aSDavid Pacheco clear_props(char *dataset, nvlist_t *props, nvlist_t *newprops) 2454745cd3c5Smaybee { 2455745cd3c5Smaybee zfs_cmd_t *zc; 2456745cd3c5Smaybee nvpair_t *prop; 2457745cd3c5Smaybee 2458745cd3c5Smaybee if (props == NULL) 2459745cd3c5Smaybee return; 2460745cd3c5Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 2461745cd3c5Smaybee (void) strcpy(zc->zc_name, dataset); 2462745cd3c5Smaybee for (prop = nvlist_next_nvpair(props, NULL); prop; 2463745cd3c5Smaybee prop = nvlist_next_nvpair(props, prop)) { 24646e77af0aSDavid Pacheco if (newprops != NULL && 24656e77af0aSDavid Pacheco nvlist_exists(newprops, nvpair_name(prop))) 24666e77af0aSDavid Pacheco continue; 2467745cd3c5Smaybee (void) strcpy(zc->zc_value, nvpair_name(prop)); 2468745cd3c5Smaybee if (zfs_secpolicy_inherit(zc, CRED()) == 0) 2469745cd3c5Smaybee (void) zfs_ioc_inherit_prop(zc); 2470745cd3c5Smaybee } 2471745cd3c5Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 2472745cd3c5Smaybee } 2473745cd3c5Smaybee 24743cb34c60Sahrens /* 24753cb34c60Sahrens * inputs: 24763cb34c60Sahrens * zc_name name of containing filesystem 24773cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 24783cb34c60Sahrens * zc_value name of snapshot to create 24793cb34c60Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 24803cb34c60Sahrens * zc_cookie file descriptor to recv from 24813cb34c60Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 24823cb34c60Sahrens * zc_guid force flag 24833cb34c60Sahrens * 24843cb34c60Sahrens * outputs: 24853cb34c60Sahrens * zc_cookie number of bytes read 24863cb34c60Sahrens */ 2487fa9e4066Sahrens static int 24883cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 2489fa9e4066Sahrens { 2490fa9e4066Sahrens file_t *fp; 2491f18faf3fSek objset_t *os; 24923cb34c60Sahrens dmu_recv_cookie_t drc; 2493f18faf3fSek zfsvfs_t *zfsvfs = NULL; 2494f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 2495f18faf3fSek int error, fd; 24963cb34c60Sahrens offset_t off; 24973cb34c60Sahrens nvlist_t *props = NULL; 2498745cd3c5Smaybee nvlist_t *origprops = NULL; 24993cb34c60Sahrens objset_t *origin = NULL; 25003cb34c60Sahrens char *tosnap; 25013cb34c60Sahrens char tofs[ZFS_MAXNAMELEN]; 2502fa9e4066Sahrens 25033ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2504f18faf3fSek strchr(zc->zc_value, '@') == NULL || 2505f18faf3fSek strchr(zc->zc_value, '%')) 25063ccfa83cSahrens return (EINVAL); 25073ccfa83cSahrens 25083cb34c60Sahrens (void) strcpy(tofs, zc->zc_value); 25093cb34c60Sahrens tosnap = strchr(tofs, '@'); 25103cb34c60Sahrens *tosnap = '\0'; 25113cb34c60Sahrens tosnap++; 25123cb34c60Sahrens 25133cb34c60Sahrens if (zc->zc_nvlist_src != NULL && 25143cb34c60Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 25153cb34c60Sahrens &props)) != 0) 25163cb34c60Sahrens return (error); 25173cb34c60Sahrens 2518fa9e4066Sahrens fd = zc->zc_cookie; 2519fa9e4066Sahrens fp = getf(fd); 25203cb34c60Sahrens if (fp == NULL) { 25213cb34c60Sahrens nvlist_free(props); 2522fa9e4066Sahrens return (EBADF); 25233cb34c60Sahrens } 2524f18faf3fSek 2525745cd3c5Smaybee if (dmu_objset_open(tofs, DMU_OST_ANY, 2526745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 2527745cd3c5Smaybee /* 2528745cd3c5Smaybee * Try to get the zfsvfs for the receiving objset. 2529745cd3c5Smaybee * There won't be one if we're operating on a zvol, 2530745cd3c5Smaybee * if the objset doesn't exist yet, or is not mounted. 2531745cd3c5Smaybee */ 25324ccbb6e7Sahrens mutex_enter(&os->os->os_user_ptr_lock); 2533745cd3c5Smaybee if (zfsvfs = dmu_objset_get_user(os)) { 253447f263f4Sek if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) { 2535745cd3c5Smaybee mutex_exit(&os->os->os_user_ptr_lock); 253647f263f4Sek dmu_objset_close(os); 2537745cd3c5Smaybee zfsvfs = NULL; 2538745cd3c5Smaybee error = EBUSY; 2539745cd3c5Smaybee goto out; 254047f263f4Sek } 2541745cd3c5Smaybee VFS_HOLD(zfsvfs->z_vfs); 254247f263f4Sek } 2543745cd3c5Smaybee mutex_exit(&os->os->os_user_ptr_lock); 2544745cd3c5Smaybee 2545745cd3c5Smaybee /* 2546745cd3c5Smaybee * If new properties are supplied, they are to completely 2547745cd3c5Smaybee * replace the existing ones, so stash away the existing ones. 2548745cd3c5Smaybee */ 2549745cd3c5Smaybee if (props) 2550745cd3c5Smaybee (void) dsl_prop_get_all(os, &origprops, TRUE); 2551745cd3c5Smaybee 2552f18faf3fSek dmu_objset_close(os); 2553f18faf3fSek } 2554f18faf3fSek 25553cb34c60Sahrens if (zc->zc_string[0]) { 25563cb34c60Sahrens error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 2557745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &origin); 2558745cd3c5Smaybee if (error) 2559745cd3c5Smaybee goto out; 25603cb34c60Sahrens } 25613cb34c60Sahrens 25623cb34c60Sahrens error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 25633cb34c60Sahrens force, origin, zfsvfs != NULL, &drc); 25643cb34c60Sahrens if (origin) 25653cb34c60Sahrens dmu_objset_close(origin); 2566745cd3c5Smaybee if (error) 2567745cd3c5Smaybee goto out; 2568f18faf3fSek 2569f18faf3fSek /* 2570745cd3c5Smaybee * Reset properties. We do this before we receive the stream 2571745cd3c5Smaybee * so that the properties are applied to the new data. 2572f18faf3fSek */ 25733cb34c60Sahrens if (props) { 25746e77af0aSDavid Pacheco clear_props(tofs, origprops, props); 2575745cd3c5Smaybee /* 2576745cd3c5Smaybee * XXX - Note, this is all-or-nothing; should be best-effort. 2577745cd3c5Smaybee */ 2578745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, props); 25793cb34c60Sahrens } 25803cb34c60Sahrens 25813cb34c60Sahrens off = fp->f_offset; 25823cb34c60Sahrens error = dmu_recv_stream(&drc, fp->f_vnode, &off); 2583a2eea2e1Sahrens 2584745cd3c5Smaybee if (error == 0 && zfsvfs) { 25856a0f0066SEric Taylor char *osname; 2586745cd3c5Smaybee int mode; 2587745cd3c5Smaybee 2588745cd3c5Smaybee /* online recv */ 25896a0f0066SEric Taylor osname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 2590745cd3c5Smaybee error = zfs_suspend_fs(zfsvfs, osname, &mode); 2591745cd3c5Smaybee if (error == 0) { 2592745cd3c5Smaybee int resume_err; 2593745cd3c5Smaybee 25943cb34c60Sahrens error = dmu_recv_end(&drc); 2595745cd3c5Smaybee resume_err = zfs_resume_fs(zfsvfs, osname, mode); 2596745cd3c5Smaybee error = error ? error : resume_err; 2597745cd3c5Smaybee } else { 2598745cd3c5Smaybee dmu_recv_abort_cleanup(&drc); 25993cb34c60Sahrens } 26006a0f0066SEric Taylor kmem_free(osname, MAXNAMELEN); 2601745cd3c5Smaybee } else if (error == 0) { 2602745cd3c5Smaybee error = dmu_recv_end(&drc); 260347f263f4Sek } 26043cb34c60Sahrens 26053cb34c60Sahrens zc->zc_cookie = off - fp->f_offset; 26063cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 26073cb34c60Sahrens fp->f_offset = off; 2608a2eea2e1Sahrens 2609745cd3c5Smaybee /* 2610745cd3c5Smaybee * On error, restore the original props. 2611745cd3c5Smaybee */ 2612745cd3c5Smaybee if (error && props) { 26136e77af0aSDavid Pacheco clear_props(tofs, props, NULL); 2614745cd3c5Smaybee (void) zfs_set_prop_nvlist(tofs, origprops); 2615745cd3c5Smaybee } 2616745cd3c5Smaybee out: 2617745cd3c5Smaybee if (zfsvfs) { 2618745cd3c5Smaybee mutex_exit(&zfsvfs->z_online_recv_lock); 2619745cd3c5Smaybee VFS_RELE(zfsvfs->z_vfs); 2620745cd3c5Smaybee } 2621745cd3c5Smaybee nvlist_free(props); 2622745cd3c5Smaybee nvlist_free(origprops); 2623fa9e4066Sahrens releasef(fd); 2624fa9e4066Sahrens return (error); 2625fa9e4066Sahrens } 2626fa9e4066Sahrens 26273cb34c60Sahrens /* 26283cb34c60Sahrens * inputs: 26293cb34c60Sahrens * zc_name name of snapshot to send 26303cb34c60Sahrens * zc_value short name of incremental fromsnap (may be empty) 26313cb34c60Sahrens * zc_cookie file descriptor to send stream to 26323cb34c60Sahrens * zc_obj fromorigin flag (mutually exclusive with zc_value) 26333cb34c60Sahrens * 26343cb34c60Sahrens * outputs: none 26353cb34c60Sahrens */ 2636fa9e4066Sahrens static int 26373cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 2638fa9e4066Sahrens { 2639fa9e4066Sahrens objset_t *fromsnap = NULL; 2640fa9e4066Sahrens objset_t *tosnap; 2641fa9e4066Sahrens file_t *fp; 2642fa9e4066Sahrens int error; 26433cb34c60Sahrens offset_t off; 2644fa9e4066Sahrens 2645fa9e4066Sahrens error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 2646745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &tosnap); 2647fa9e4066Sahrens if (error) 2648fa9e4066Sahrens return (error); 2649fa9e4066Sahrens 2650e9dbad6fSeschrock if (zc->zc_value[0] != '\0') { 26516a0f0066SEric Taylor char *buf; 2652a2eea2e1Sahrens char *cp; 2653a2eea2e1Sahrens 26546a0f0066SEric Taylor buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 26556a0f0066SEric Taylor (void) strncpy(buf, zc->zc_name, MAXPATHLEN); 2656a2eea2e1Sahrens cp = strchr(buf, '@'); 2657a2eea2e1Sahrens if (cp) 2658a2eea2e1Sahrens *(cp+1) = 0; 26596a0f0066SEric Taylor (void) strncat(buf, zc->zc_value, MAXPATHLEN); 2660a2eea2e1Sahrens error = dmu_objset_open(buf, DMU_OST_ANY, 2661745cd3c5Smaybee DS_MODE_USER | DS_MODE_READONLY, &fromsnap); 26626a0f0066SEric Taylor kmem_free(buf, MAXPATHLEN); 2663fa9e4066Sahrens if (error) { 2664fa9e4066Sahrens dmu_objset_close(tosnap); 2665fa9e4066Sahrens return (error); 2666fa9e4066Sahrens } 2667fa9e4066Sahrens } 2668fa9e4066Sahrens 2669fa9e4066Sahrens fp = getf(zc->zc_cookie); 2670fa9e4066Sahrens if (fp == NULL) { 2671fa9e4066Sahrens dmu_objset_close(tosnap); 2672fa9e4066Sahrens if (fromsnap) 2673fa9e4066Sahrens dmu_objset_close(fromsnap); 2674fa9e4066Sahrens return (EBADF); 2675fa9e4066Sahrens } 2676fa9e4066Sahrens 26773cb34c60Sahrens off = fp->f_offset; 26783cb34c60Sahrens error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); 2679fa9e4066Sahrens 26803cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 26813cb34c60Sahrens fp->f_offset = off; 2682fa9e4066Sahrens releasef(zc->zc_cookie); 2683fa9e4066Sahrens if (fromsnap) 2684fa9e4066Sahrens dmu_objset_close(fromsnap); 2685fa9e4066Sahrens dmu_objset_close(tosnap); 2686fa9e4066Sahrens return (error); 2687fa9e4066Sahrens } 2688fa9e4066Sahrens 2689ea8dc4b6Seschrock static int 2690ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 2691ea8dc4b6Seschrock { 2692ea8dc4b6Seschrock int id, error; 2693ea8dc4b6Seschrock 2694ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2695ea8dc4b6Seschrock &zc->zc_inject_record); 2696ea8dc4b6Seschrock 2697ea8dc4b6Seschrock if (error == 0) 2698ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 2699ea8dc4b6Seschrock 2700ea8dc4b6Seschrock return (error); 2701ea8dc4b6Seschrock } 2702ea8dc4b6Seschrock 2703ea8dc4b6Seschrock static int 2704ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 2705ea8dc4b6Seschrock { 2706ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 2707ea8dc4b6Seschrock } 2708ea8dc4b6Seschrock 2709ea8dc4b6Seschrock static int 2710ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 2711ea8dc4b6Seschrock { 2712ea8dc4b6Seschrock int id = (int)zc->zc_guid; 2713ea8dc4b6Seschrock int error; 2714ea8dc4b6Seschrock 2715ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2716ea8dc4b6Seschrock &zc->zc_inject_record); 2717ea8dc4b6Seschrock 2718ea8dc4b6Seschrock zc->zc_guid = id; 2719ea8dc4b6Seschrock 2720ea8dc4b6Seschrock return (error); 2721ea8dc4b6Seschrock } 2722ea8dc4b6Seschrock 2723ea8dc4b6Seschrock static int 2724ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 2725ea8dc4b6Seschrock { 2726ea8dc4b6Seschrock spa_t *spa; 2727ea8dc4b6Seschrock int error; 2728e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 2729ea8dc4b6Seschrock 2730ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2731ea8dc4b6Seschrock return (error); 2732ea8dc4b6Seschrock 2733e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2734ea8dc4b6Seschrock &count); 2735ea8dc4b6Seschrock if (error == 0) 2736e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 2737ea8dc4b6Seschrock else 2738e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2739ea8dc4b6Seschrock 2740ea8dc4b6Seschrock spa_close(spa, FTAG); 2741ea8dc4b6Seschrock 2742ea8dc4b6Seschrock return (error); 2743ea8dc4b6Seschrock } 2744ea8dc4b6Seschrock 2745ea8dc4b6Seschrock static int 2746ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 2747ea8dc4b6Seschrock { 2748ea8dc4b6Seschrock spa_t *spa; 2749ea8dc4b6Seschrock vdev_t *vd; 2750bb8b5132Sek int error; 2751ea8dc4b6Seschrock 2752b87f3af3Sperrin /* 2753b87f3af3Sperrin * On zpool clear we also fix up missing slogs 2754b87f3af3Sperrin */ 2755b87f3af3Sperrin mutex_enter(&spa_namespace_lock); 2756b87f3af3Sperrin spa = spa_lookup(zc->zc_name); 2757b87f3af3Sperrin if (spa == NULL) { 2758b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 2759b87f3af3Sperrin return (EIO); 2760b87f3af3Sperrin } 2761b87f3af3Sperrin if (spa->spa_log_state == SPA_LOG_MISSING) { 2762b87f3af3Sperrin /* we need to let spa_open/spa_load clear the chains */ 2763b87f3af3Sperrin spa->spa_log_state = SPA_LOG_CLEAR; 2764b87f3af3Sperrin } 2765b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 2766b87f3af3Sperrin 2767ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2768ea8dc4b6Seschrock return (error); 2769ea8dc4b6Seschrock 2770e14bb325SJeff Bonwick spa_vdev_state_enter(spa); 2771ea8dc4b6Seschrock 2772e9dbad6fSeschrock if (zc->zc_guid == 0) { 2773ea8dc4b6Seschrock vd = NULL; 2774c5904d13Seschrock } else { 2775c5904d13Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 2776fa94a07fSbrendan if (vd == NULL) { 2777e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, ENODEV); 2778fa94a07fSbrendan spa_close(spa, FTAG); 2779fa94a07fSbrendan return (ENODEV); 2780fa94a07fSbrendan } 2781ea8dc4b6Seschrock } 2782ea8dc4b6Seschrock 2783e14bb325SJeff Bonwick vdev_clear(spa, vd); 2784e14bb325SJeff Bonwick 2785e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, 0); 2786ea8dc4b6Seschrock 2787e14bb325SJeff Bonwick /* 2788e14bb325SJeff Bonwick * Resume any suspended I/Os. 2789e14bb325SJeff Bonwick */ 2790e14bb325SJeff Bonwick zio_resume(spa); 2791ea8dc4b6Seschrock 2792ea8dc4b6Seschrock spa_close(spa, FTAG); 2793ea8dc4b6Seschrock 2794ea8dc4b6Seschrock return (0); 2795ea8dc4b6Seschrock } 2796ea8dc4b6Seschrock 27973cb34c60Sahrens /* 27983cb34c60Sahrens * inputs: 27993cb34c60Sahrens * zc_name name of filesystem 28003cb34c60Sahrens * zc_value name of origin snapshot 28013cb34c60Sahrens * 28023cb34c60Sahrens * outputs: none 28033cb34c60Sahrens */ 280499653d4eSeschrock static int 280599653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 280699653d4eSeschrock { 28070b69c2f0Sahrens char *cp; 28080b69c2f0Sahrens 28090b69c2f0Sahrens /* 28100b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 28110b69c2f0Sahrens * it's easier. 28120b69c2f0Sahrens */ 2813e9dbad6fSeschrock cp = strchr(zc->zc_value, '@'); 28140b69c2f0Sahrens if (cp) 28150b69c2f0Sahrens *cp = '\0'; 2816e9dbad6fSeschrock (void) dmu_objset_find(zc->zc_value, 28170b69c2f0Sahrens zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 281899653d4eSeschrock return (dsl_dataset_promote(zc->zc_name)); 281999653d4eSeschrock } 282099653d4eSeschrock 2821ecd6cf80Smarks /* 2822ecd6cf80Smarks * We don't want to have a hard dependency 2823ecd6cf80Smarks * against some special symbols in sharefs 2824da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 2825ecd6cf80Smarks * the first file system is shared. 2826da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 2827ecd6cf80Smarks */ 2828da6c28aaSamw int (*znfsexport_fs)(void *arg); 2829ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2830da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 2831da6c28aaSamw 2832da6c28aaSamw int zfs_nfsshare_inited; 2833da6c28aaSamw int zfs_smbshare_inited; 2834ecd6cf80Smarks 2835ecd6cf80Smarks ddi_modhandle_t nfs_mod; 2836ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 2837da6c28aaSamw ddi_modhandle_t smbsrv_mod; 2838ecd6cf80Smarks kmutex_t zfs_share_lock; 2839ecd6cf80Smarks 2840da6c28aaSamw static int 2841da6c28aaSamw zfs_init_sharefs() 2842da6c28aaSamw { 2843da6c28aaSamw int error; 2844da6c28aaSamw 2845da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 2846da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 2847da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 2848da6c28aaSamw ddi_modopen("fs/sharefs", 2849da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2850da6c28aaSamw return (ENOSYS); 2851da6c28aaSamw } 2852da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 2853da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2854da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2855da6c28aaSamw return (ENOSYS); 2856da6c28aaSamw } 2857da6c28aaSamw return (0); 2858da6c28aaSamw } 2859da6c28aaSamw 2860ecd6cf80Smarks static int 2861ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 2862ecd6cf80Smarks { 2863ecd6cf80Smarks int error; 2864ecd6cf80Smarks int opcode; 2865ecd6cf80Smarks 2866da6c28aaSamw switch (zc->zc_share.z_sharetype) { 2867da6c28aaSamw case ZFS_SHARE_NFS: 2868da6c28aaSamw case ZFS_UNSHARE_NFS: 2869da6c28aaSamw if (zfs_nfsshare_inited == 0) { 2870da6c28aaSamw mutex_enter(&zfs_share_lock); 2871da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 2872da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2873da6c28aaSamw mutex_exit(&zfs_share_lock); 2874da6c28aaSamw return (ENOSYS); 2875da6c28aaSamw } 2876da6c28aaSamw if (znfsexport_fs == NULL && 2877da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 2878da6c28aaSamw ddi_modsym(nfs_mod, 2879da6c28aaSamw "nfs_export", &error)) == NULL)) { 2880da6c28aaSamw mutex_exit(&zfs_share_lock); 2881da6c28aaSamw return (ENOSYS); 2882da6c28aaSamw } 2883da6c28aaSamw error = zfs_init_sharefs(); 2884da6c28aaSamw if (error) { 2885da6c28aaSamw mutex_exit(&zfs_share_lock); 2886da6c28aaSamw return (ENOSYS); 2887da6c28aaSamw } 2888da6c28aaSamw zfs_nfsshare_inited = 1; 2889ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2890ecd6cf80Smarks } 2891da6c28aaSamw break; 2892da6c28aaSamw case ZFS_SHARE_SMB: 2893da6c28aaSamw case ZFS_UNSHARE_SMB: 2894da6c28aaSamw if (zfs_smbshare_inited == 0) { 2895da6c28aaSamw mutex_enter(&zfs_share_lock); 2896da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 2897da6c28aaSamw ddi_modopen("drv/smbsrv", 2898da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 2899da6c28aaSamw mutex_exit(&zfs_share_lock); 2900da6c28aaSamw return (ENOSYS); 2901da6c28aaSamw } 2902da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 2903da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 2904faa1795aSjb "smb_server_share", &error)) == NULL)) { 2905da6c28aaSamw mutex_exit(&zfs_share_lock); 2906da6c28aaSamw return (ENOSYS); 2907da6c28aaSamw } 2908da6c28aaSamw error = zfs_init_sharefs(); 2909da6c28aaSamw if (error) { 2910da6c28aaSamw mutex_exit(&zfs_share_lock); 2911da6c28aaSamw return (ENOSYS); 2912da6c28aaSamw } 2913da6c28aaSamw zfs_smbshare_inited = 1; 2914ecd6cf80Smarks mutex_exit(&zfs_share_lock); 2915ecd6cf80Smarks } 2916da6c28aaSamw break; 2917da6c28aaSamw default: 2918da6c28aaSamw return (EINVAL); 2919da6c28aaSamw } 2920ecd6cf80Smarks 2921da6c28aaSamw switch (zc->zc_share.z_sharetype) { 2922da6c28aaSamw case ZFS_SHARE_NFS: 2923da6c28aaSamw case ZFS_UNSHARE_NFS: 2924da6c28aaSamw if (error = 2925da6c28aaSamw znfsexport_fs((void *) 2926da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 2927da6c28aaSamw return (error); 2928da6c28aaSamw break; 2929da6c28aaSamw case ZFS_SHARE_SMB: 2930da6c28aaSamw case ZFS_UNSHARE_SMB: 2931da6c28aaSamw if (error = zsmbexport_fs((void *) 2932da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 2933da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 2934*743a77edSAlan Wright B_TRUE: B_FALSE)) { 2935da6c28aaSamw return (error); 2936ecd6cf80Smarks } 2937da6c28aaSamw break; 2938ecd6cf80Smarks } 2939ecd6cf80Smarks 2940da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 2941da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 2942ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 2943ecd6cf80Smarks 2944da6c28aaSamw /* 2945da6c28aaSamw * Add or remove share from sharetab 2946da6c28aaSamw */ 2947ecd6cf80Smarks error = zshare_fs(opcode, 2948ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 2949ecd6cf80Smarks zc->zc_share.z_sharemax); 2950ecd6cf80Smarks 2951ecd6cf80Smarks return (error); 2952ecd6cf80Smarks 2953ecd6cf80Smarks } 2954ecd6cf80Smarks 2955*743a77edSAlan Wright ace_t full_access[] = { 2956*743a77edSAlan Wright {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 2957*743a77edSAlan Wright }; 2958*743a77edSAlan Wright 2959*743a77edSAlan Wright /* 2960*743a77edSAlan Wright * Remove all ACL files in shares dir 2961*743a77edSAlan Wright */ 2962*743a77edSAlan Wright static int 2963*743a77edSAlan Wright zfs_smb_acl_purge(znode_t *dzp) 2964*743a77edSAlan Wright { 2965*743a77edSAlan Wright zap_cursor_t zc; 2966*743a77edSAlan Wright zap_attribute_t zap; 2967*743a77edSAlan Wright zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 2968*743a77edSAlan Wright int error; 2969*743a77edSAlan Wright 2970*743a77edSAlan Wright for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 2971*743a77edSAlan Wright (error = zap_cursor_retrieve(&zc, &zap)) == 0; 2972*743a77edSAlan Wright zap_cursor_advance(&zc)) { 2973*743a77edSAlan Wright if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 2974*743a77edSAlan Wright NULL, 0)) != 0) 2975*743a77edSAlan Wright break; 2976*743a77edSAlan Wright } 2977*743a77edSAlan Wright zap_cursor_fini(&zc); 2978*743a77edSAlan Wright return (error); 2979*743a77edSAlan Wright } 2980*743a77edSAlan Wright 2981*743a77edSAlan Wright static int 2982*743a77edSAlan Wright zfs_ioc_smb_acl(zfs_cmd_t *zc) 2983*743a77edSAlan Wright { 2984*743a77edSAlan Wright vnode_t *vp; 2985*743a77edSAlan Wright znode_t *dzp; 2986*743a77edSAlan Wright vnode_t *resourcevp = NULL; 2987*743a77edSAlan Wright znode_t *sharedir; 2988*743a77edSAlan Wright zfsvfs_t *zfsvfs; 2989*743a77edSAlan Wright nvlist_t *nvlist; 2990*743a77edSAlan Wright char *src, *target; 2991*743a77edSAlan Wright vattr_t vattr; 2992*743a77edSAlan Wright vsecattr_t vsec; 2993*743a77edSAlan Wright int error = 0; 2994*743a77edSAlan Wright 2995*743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 2996*743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 2997*743a77edSAlan Wright return (error); 2998*743a77edSAlan Wright 2999*743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 3000*743a77edSAlan Wright 3001*743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 3002*743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 3003*743a77edSAlan Wright zc->zc_name) != 0)) { 3004*743a77edSAlan Wright VN_RELE(vp); 3005*743a77edSAlan Wright return (EINVAL); 3006*743a77edSAlan Wright } 3007*743a77edSAlan Wright 3008*743a77edSAlan Wright dzp = VTOZ(vp); 3009*743a77edSAlan Wright zfsvfs = dzp->z_zfsvfs; 3010*743a77edSAlan Wright 3011*743a77edSAlan Wright ZFS_ENTER(zfsvfs); 3012*743a77edSAlan Wright 3013*743a77edSAlan Wright if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 3014*743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3015*743a77edSAlan Wright return (error); 3016*743a77edSAlan Wright } 3017*743a77edSAlan Wright 3018*743a77edSAlan Wright switch (zc->zc_cookie) { 3019*743a77edSAlan Wright case ZFS_SMB_ACL_ADD: 3020*743a77edSAlan Wright vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 3021*743a77edSAlan Wright vattr.va_type = VREG; 3022*743a77edSAlan Wright vattr.va_mode = S_IFREG|0777; 3023*743a77edSAlan Wright vattr.va_uid = 0; 3024*743a77edSAlan Wright vattr.va_gid = 0; 3025*743a77edSAlan Wright 3026*743a77edSAlan Wright vsec.vsa_mask = VSA_ACE; 3027*743a77edSAlan Wright vsec.vsa_aclentp = &full_access; 3028*743a77edSAlan Wright vsec.vsa_aclentsz = sizeof (full_access); 3029*743a77edSAlan Wright vsec.vsa_aclcnt = 1; 3030*743a77edSAlan Wright 3031*743a77edSAlan Wright error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 3032*743a77edSAlan Wright &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 3033*743a77edSAlan Wright if (resourcevp) 3034*743a77edSAlan Wright VN_RELE(resourcevp); 3035*743a77edSAlan Wright break; 3036*743a77edSAlan Wright 3037*743a77edSAlan Wright case ZFS_SMB_ACL_REMOVE: 3038*743a77edSAlan Wright error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 3039*743a77edSAlan Wright NULL, 0); 3040*743a77edSAlan Wright break; 3041*743a77edSAlan Wright 3042*743a77edSAlan Wright case ZFS_SMB_ACL_RENAME: 3043*743a77edSAlan Wright if ((error = get_nvlist(zc->zc_nvlist_src, 3044*743a77edSAlan Wright zc->zc_nvlist_src_size, &nvlist)) != 0) { 3045*743a77edSAlan Wright VN_RELE(vp); 3046*743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3047*743a77edSAlan Wright return (error); 3048*743a77edSAlan Wright } 3049*743a77edSAlan Wright if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 3050*743a77edSAlan Wright nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 3051*743a77edSAlan Wright &target)) { 3052*743a77edSAlan Wright VN_RELE(vp); 3053*743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3054*743a77edSAlan Wright return (error); 3055*743a77edSAlan Wright } 3056*743a77edSAlan Wright error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 3057*743a77edSAlan Wright kcred, NULL, 0); 3058*743a77edSAlan Wright nvlist_free(nvlist); 3059*743a77edSAlan Wright break; 3060*743a77edSAlan Wright 3061*743a77edSAlan Wright case ZFS_SMB_ACL_PURGE: 3062*743a77edSAlan Wright error = zfs_smb_acl_purge(sharedir); 3063*743a77edSAlan Wright break; 3064*743a77edSAlan Wright 3065*743a77edSAlan Wright default: 3066*743a77edSAlan Wright error = EINVAL; 3067*743a77edSAlan Wright break; 3068*743a77edSAlan Wright } 3069*743a77edSAlan Wright 3070*743a77edSAlan Wright VN_RELE(vp); 3071*743a77edSAlan Wright VN_RELE(ZTOV(sharedir)); 3072*743a77edSAlan Wright 3073*743a77edSAlan Wright ZFS_EXIT(zfsvfs); 3074*743a77edSAlan Wright 3075*743a77edSAlan Wright return (error); 3076*743a77edSAlan Wright } 3077*743a77edSAlan Wright 3078ecd6cf80Smarks /* 30792a6b87f0Sek * pool create, destroy, and export don't log the history as part of 30802a6b87f0Sek * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 30812a6b87f0Sek * do the logging of those commands. 3082ecd6cf80Smarks */ 3083fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = { 3084228975ccSek { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 3085e7437265Sahrens { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 3086e7437265Sahrens { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3087e7437265Sahrens { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 3088e7437265Sahrens { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 3089e7437265Sahrens { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 3090e7437265Sahrens { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 3091e7437265Sahrens { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3092e7437265Sahrens { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 3093e7437265Sahrens { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3094e7437265Sahrens { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 3095e7437265Sahrens { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3096e7437265Sahrens { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3097e7437265Sahrens { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3098e7437265Sahrens { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3099e7437265Sahrens { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3100e7437265Sahrens { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 3101e7437265Sahrens { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 3102de8267e0Stimh { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 3103ecd6cf80Smarks { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 3104e7437265Sahrens DATASET_NAME, B_FALSE }, 3105ecd6cf80Smarks { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 3106e7437265Sahrens DATASET_NAME, B_FALSE }, 3107e7437265Sahrens { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 3108e7437265Sahrens { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 3109e7437265Sahrens { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 3110e7437265Sahrens { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 3111e7437265Sahrens { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 3112e7437265Sahrens { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 3113e7437265Sahrens { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 31143cb34c60Sahrens { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 31153cb34c60Sahrens { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 3116e7437265Sahrens { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 3117e7437265Sahrens { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 3118e7437265Sahrens { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 3119e7437265Sahrens { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 3120e7437265Sahrens { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3121e7437265Sahrens { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 3122e7437265Sahrens { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 3123e7437265Sahrens { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 3124e7437265Sahrens { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 3125e7437265Sahrens { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 3126e7437265Sahrens { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 3127e7437265Sahrens { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 3128e7437265Sahrens { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 3129e7437265Sahrens { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 3130ecd6cf80Smarks { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 3131e7437265Sahrens DATASET_NAME, B_FALSE }, 3132e45ce728Sahrens { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 3133e45ce728Sahrens { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 3134*743a77edSAlan Wright { zfs_ioc_smb_acl, zfs_secpolicy_smb_acl, DATASET_NAME, B_FALSE } 3135fa9e4066Sahrens }; 3136fa9e4066Sahrens 3137fa9e4066Sahrens static int 3138fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 3139fa9e4066Sahrens { 3140fa9e4066Sahrens zfs_cmd_t *zc; 3141fa9e4066Sahrens uint_t vec; 31421d452cf5Sahrens int error, rc; 3143fa9e4066Sahrens 3144fa9e4066Sahrens if (getminor(dev) != 0) 3145fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 3146fa9e4066Sahrens 3147fa9e4066Sahrens vec = cmd - ZFS_IOC; 314891ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 3149fa9e4066Sahrens 3150fa9e4066Sahrens if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 3151fa9e4066Sahrens return (EINVAL); 3152fa9e4066Sahrens 3153fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 3154fa9e4066Sahrens 3155fa9e4066Sahrens error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); 3156fa9e4066Sahrens 315791ebeef5Sahrens if (error == 0) 3158ecd6cf80Smarks error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); 3159fa9e4066Sahrens 3160fa9e4066Sahrens /* 3161fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 3162fa9e4066Sahrens * the lower layers. 3163fa9e4066Sahrens */ 3164fa9e4066Sahrens if (error == 0) { 3165fa9e4066Sahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 3166fa9e4066Sahrens switch (zfs_ioc_vec[vec].zvec_namecheck) { 3167e7437265Sahrens case POOL_NAME: 3168fa9e4066Sahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 3169fa9e4066Sahrens error = EINVAL; 3170fa9e4066Sahrens break; 3171fa9e4066Sahrens 3172e7437265Sahrens case DATASET_NAME: 3173fa9e4066Sahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 3174fa9e4066Sahrens error = EINVAL; 3175fa9e4066Sahrens break; 31765ad82045Snd 3177e7437265Sahrens case NO_NAME: 31785ad82045Snd break; 3179fa9e4066Sahrens } 3180fa9e4066Sahrens } 3181fa9e4066Sahrens 3182fa9e4066Sahrens if (error == 0) 3183fa9e4066Sahrens error = zfs_ioc_vec[vec].zvec_func(zc); 3184fa9e4066Sahrens 31851d452cf5Sahrens rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); 3186ecd6cf80Smarks if (error == 0) { 31871d452cf5Sahrens error = rc; 3188ecd6cf80Smarks if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 3189ecd6cf80Smarks zfs_log_history(zc); 3190ecd6cf80Smarks } 3191fa9e4066Sahrens 3192fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 3193fa9e4066Sahrens return (error); 3194fa9e4066Sahrens } 3195fa9e4066Sahrens 3196fa9e4066Sahrens static int 3197fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3198fa9e4066Sahrens { 3199fa9e4066Sahrens if (cmd != DDI_ATTACH) 3200fa9e4066Sahrens return (DDI_FAILURE); 3201fa9e4066Sahrens 3202fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 3203fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 3204fa9e4066Sahrens return (DDI_FAILURE); 3205fa9e4066Sahrens 3206fa9e4066Sahrens zfs_dip = dip; 3207fa9e4066Sahrens 3208fa9e4066Sahrens ddi_report_dev(dip); 3209fa9e4066Sahrens 3210fa9e4066Sahrens return (DDI_SUCCESS); 3211fa9e4066Sahrens } 3212fa9e4066Sahrens 3213fa9e4066Sahrens static int 3214fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3215fa9e4066Sahrens { 3216fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 3217fa9e4066Sahrens return (DDI_FAILURE); 3218fa9e4066Sahrens 3219fa9e4066Sahrens if (cmd != DDI_DETACH) 3220fa9e4066Sahrens return (DDI_FAILURE); 3221fa9e4066Sahrens 3222fa9e4066Sahrens zfs_dip = NULL; 3223fa9e4066Sahrens 3224fa9e4066Sahrens ddi_prop_remove_all(dip); 3225fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 3226fa9e4066Sahrens 3227fa9e4066Sahrens return (DDI_SUCCESS); 3228fa9e4066Sahrens } 3229fa9e4066Sahrens 3230fa9e4066Sahrens /*ARGSUSED*/ 3231fa9e4066Sahrens static int 3232fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3233fa9e4066Sahrens { 3234fa9e4066Sahrens switch (infocmd) { 3235fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 3236fa9e4066Sahrens *result = zfs_dip; 3237fa9e4066Sahrens return (DDI_SUCCESS); 3238fa9e4066Sahrens 3239fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 3240a0965f35Sbonwick *result = (void *)0; 3241fa9e4066Sahrens return (DDI_SUCCESS); 3242fa9e4066Sahrens } 3243fa9e4066Sahrens 3244fa9e4066Sahrens return (DDI_FAILURE); 3245fa9e4066Sahrens } 3246fa9e4066Sahrens 3247fa9e4066Sahrens /* 3248fa9e4066Sahrens * OK, so this is a little weird. 3249fa9e4066Sahrens * 3250fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 3251fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3252fa9e4066Sahrens * 3253fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 3254fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 3255fa9e4066Sahrens */ 3256fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 3257fa9e4066Sahrens zvol_open, /* open */ 3258fa9e4066Sahrens zvol_close, /* close */ 3259fa9e4066Sahrens zvol_strategy, /* strategy */ 3260fa9e4066Sahrens nodev, /* print */ 3261e7cbe64fSgw zvol_dump, /* dump */ 3262fa9e4066Sahrens zvol_read, /* read */ 3263fa9e4066Sahrens zvol_write, /* write */ 3264fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 3265fa9e4066Sahrens nodev, /* devmap */ 3266fa9e4066Sahrens nodev, /* mmap */ 3267fa9e4066Sahrens nodev, /* segmap */ 3268fa9e4066Sahrens nochpoll, /* poll */ 3269fa9e4066Sahrens ddi_prop_op, /* prop_op */ 3270fa9e4066Sahrens NULL, /* streamtab */ 3271fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 3272fa9e4066Sahrens CB_REV, /* version */ 3273feb08c6bSbillm nodev, /* async read */ 3274feb08c6bSbillm nodev, /* async write */ 3275fa9e4066Sahrens }; 3276fa9e4066Sahrens 3277fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 3278fa9e4066Sahrens DEVO_REV, /* version */ 3279fa9e4066Sahrens 0, /* refcnt */ 3280fa9e4066Sahrens zfs_info, /* info */ 3281fa9e4066Sahrens nulldev, /* identify */ 3282fa9e4066Sahrens nulldev, /* probe */ 3283fa9e4066Sahrens zfs_attach, /* attach */ 3284fa9e4066Sahrens zfs_detach, /* detach */ 3285fa9e4066Sahrens nodev, /* reset */ 3286fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 328719397407SSherry Moore NULL, /* no bus operations */ 328819397407SSherry Moore NULL, /* power */ 328919397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 3290fa9e4066Sahrens }; 3291fa9e4066Sahrens 3292fa9e4066Sahrens static struct modldrv zfs_modldrv = { 329319397407SSherry Moore &mod_driverops, 329419397407SSherry Moore "ZFS storage pool", 329519397407SSherry Moore &zfs_dev_ops 3296fa9e4066Sahrens }; 3297fa9e4066Sahrens 3298fa9e4066Sahrens static struct modlinkage modlinkage = { 3299fa9e4066Sahrens MODREV_1, 3300fa9e4066Sahrens (void *)&zfs_modlfs, 3301fa9e4066Sahrens (void *)&zfs_modldrv, 3302fa9e4066Sahrens NULL 3303fa9e4066Sahrens }; 3304fa9e4066Sahrens 3305ec533521Sfr 3306ec533521Sfr uint_t zfs_fsyncer_key; 3307f18faf3fSek extern uint_t rrw_tsd_key; 3308ec533521Sfr 3309fa9e4066Sahrens int 3310fa9e4066Sahrens _init(void) 3311fa9e4066Sahrens { 3312fa9e4066Sahrens int error; 3313fa9e4066Sahrens 3314a0965f35Sbonwick spa_init(FREAD | FWRITE); 3315a0965f35Sbonwick zfs_init(); 3316a0965f35Sbonwick zvol_init(); 3317a0965f35Sbonwick 3318a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 3319a0965f35Sbonwick zvol_fini(); 3320a0965f35Sbonwick zfs_fini(); 3321a0965f35Sbonwick spa_fini(); 3322fa9e4066Sahrens return (error); 3323a0965f35Sbonwick } 3324fa9e4066Sahrens 3325ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 3326f18faf3fSek tsd_create(&rrw_tsd_key, NULL); 3327ec533521Sfr 3328fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 3329fa9e4066Sahrens ASSERT(error == 0); 3330ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3331fa9e4066Sahrens 3332fa9e4066Sahrens return (0); 3333fa9e4066Sahrens } 3334fa9e4066Sahrens 3335fa9e4066Sahrens int 3336fa9e4066Sahrens _fini(void) 3337fa9e4066Sahrens { 3338fa9e4066Sahrens int error; 3339fa9e4066Sahrens 3340ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 3341fa9e4066Sahrens return (EBUSY); 3342fa9e4066Sahrens 3343fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 3344fa9e4066Sahrens return (error); 3345fa9e4066Sahrens 3346fa9e4066Sahrens zvol_fini(); 3347fa9e4066Sahrens zfs_fini(); 3348fa9e4066Sahrens spa_fini(); 3349da6c28aaSamw if (zfs_nfsshare_inited) 3350ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 3351da6c28aaSamw if (zfs_smbshare_inited) 3352da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 3353da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 3354ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 3355fa9e4066Sahrens 3356ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 3357fa9e4066Sahrens ldi_ident_release(zfs_li); 3358fa9e4066Sahrens zfs_li = NULL; 3359ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 3360fa9e4066Sahrens 3361fa9e4066Sahrens return (error); 3362fa9e4066Sahrens } 3363fa9e4066Sahrens 3364fa9e4066Sahrens int 3365fa9e4066Sahrens _info(struct modinfo *modinfop) 3366fa9e4066Sahrens { 3367fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 3368fa9e4066Sahrens } 3369