zfs_ioctl.c revision 207626
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22185029Spjd * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23168404Spjd * Use is subject to license terms. 24168404Spjd */ 25168404Spjd 26168962Spjd#include <sys/types.h> 27168404Spjd#include <sys/param.h> 28168404Spjd#include <sys/systm.h> 29168404Spjd#include <sys/conf.h> 30168404Spjd#include <sys/kernel.h> 31168404Spjd#include <sys/lock.h> 32168404Spjd#include <sys/malloc.h> 33168404Spjd#include <sys/mutex.h> 34168404Spjd#include <sys/proc.h> 35168404Spjd#include <sys/errno.h> 36168404Spjd#include <sys/uio.h> 37168962Spjd#include <sys/buf.h> 38168404Spjd#include <sys/file.h> 39168404Spjd#include <sys/kmem.h> 40168404Spjd#include <sys/conf.h> 41168404Spjd#include <sys/cmn_err.h> 42168404Spjd#include <sys/stat.h> 43168404Spjd#include <sys/zfs_ioctl.h> 44185029Spjd#include <sys/zfs_znode.h> 45168404Spjd#include <sys/zap.h> 46168404Spjd#include <sys/spa.h> 47168404Spjd#include <sys/spa_impl.h> 48168404Spjd#include <sys/vdev.h> 49168404Spjd#include <sys/vdev_impl.h> 50168404Spjd#include <sys/dmu.h> 51168404Spjd#include <sys/dsl_dir.h> 52168404Spjd#include <sys/dsl_dataset.h> 53168404Spjd#include <sys/dsl_prop.h> 54185029Spjd#include <sys/dsl_deleg.h> 55185029Spjd#include <sys/dmu_objset.h> 56168962Spjd#include <sys/sunddi.h> 57168962Spjd#include <sys/policy.h> 58168962Spjd#include <sys/zone.h> 59168404Spjd#include <sys/nvpair.h> 60168404Spjd#include <sys/mount.h> 61168404Spjd#include <sys/taskqueue.h> 62168404Spjd#include <sys/sdt.h> 63168404Spjd#include <sys/varargs.h> 64168404Spjd#include <sys/fs/zfs.h> 65168404Spjd#include <sys/zfs_ctldir.h> 66185029Spjd#include <sys/zfs_dir.h> 67168404Spjd#include <sys/zvol.h> 68185029Spjd#include <sys/dmu_objset.h> 69168404Spjd 70168404Spjd#include "zfs_namecheck.h" 71168404Spjd#include "zfs_prop.h" 72185029Spjd#include "zfs_deleg.h" 73168404Spjd 74168404SpjdCTASSERT(sizeof(zfs_cmd_t) <= PAGE_SIZE); 75168404Spjd 76168404Spjdstatic struct cdev *zfsdev; 77168404Spjd 78168404Spjdextern void zfs_init(void); 79168404Spjdextern void zfs_fini(void); 80168404Spjd 81168404Spjdtypedef int zfs_ioc_func_t(zfs_cmd_t *); 82185029Spjdtypedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 83168404Spjd 84168404Spjdtypedef struct zfs_ioc_vec { 85168404Spjd zfs_ioc_func_t *zvec_func; 86168404Spjd zfs_secpolicy_func_t *zvec_secpolicy; 87168404Spjd enum { 88185029Spjd NO_NAME, 89185029Spjd POOL_NAME, 90185029Spjd DATASET_NAME 91185029Spjd } zvec_namecheck; 92185029Spjd boolean_t zvec_his_log; 93168404Spjd} zfs_ioc_vec_t; 94168404Spjd 95185029Spjdstatic void clear_props(char *dataset, nvlist_t *props); 96185029Spjdstatic int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 97185029Spjd boolean_t *); 98185029Spjdint zfs_set_prop_nvlist(const char *, nvlist_t *); 99185029Spjd 100168404Spjd/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 101168404Spjdvoid 102168404Spjd__dprintf(const char *file, const char *func, int line, const char *fmt, ...) 103168404Spjd{ 104168404Spjd const char *newfile; 105168404Spjd char buf[256]; 106168404Spjd va_list adx; 107168404Spjd 108168404Spjd /* 109168404Spjd * Get rid of annoying "../common/" prefix to filename. 110168404Spjd */ 111168404Spjd newfile = strrchr(file, '/'); 112168404Spjd if (newfile != NULL) { 113168404Spjd newfile = newfile + 1; /* Get rid of leading / */ 114168404Spjd } else { 115168404Spjd newfile = file; 116168404Spjd } 117168404Spjd 118168404Spjd va_start(adx, fmt); 119168404Spjd (void) vsnprintf(buf, sizeof (buf), fmt, adx); 120168404Spjd va_end(adx); 121168404Spjd 122168404Spjd /* 123168404Spjd * To get this data, use the zfs-dprintf probe as so: 124168404Spjd * dtrace -q -n 'zfs-dprintf \ 125168404Spjd * /stringof(arg0) == "dbuf.c"/ \ 126168404Spjd * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 127168404Spjd * arg0 = file name 128168404Spjd * arg1 = function name 129168404Spjd * arg2 = line number 130168404Spjd * arg3 = message 131168404Spjd */ 132168404Spjd DTRACE_PROBE4(zfs__dprintf, 133168404Spjd char *, newfile, char *, func, int, line, char *, buf); 134168404Spjd} 135168404Spjd 136185029Spjdstatic void 137185029Spjdhistory_str_free(char *buf) 138185029Spjd{ 139185029Spjd kmem_free(buf, HIS_MAX_RECORD_LEN); 140185029Spjd} 141185029Spjd 142185029Spjdstatic char * 143185029Spjdhistory_str_get(zfs_cmd_t *zc) 144185029Spjd{ 145185029Spjd char *buf; 146185029Spjd 147185029Spjd if (zc->zc_history == 0) 148185029Spjd return (NULL); 149185029Spjd 150185029Spjd buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 151185029Spjd if (copyinstr((void *)(uintptr_t)zc->zc_history, 152185029Spjd buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 153185029Spjd history_str_free(buf); 154185029Spjd return (NULL); 155185029Spjd } 156185029Spjd 157185029Spjd buf[HIS_MAX_RECORD_LEN -1] = '\0'; 158185029Spjd 159185029Spjd return (buf); 160185029Spjd} 161185029Spjd 162168404Spjd/* 163185029Spjd * Check to see if the named dataset is currently defined as bootable 164185029Spjd */ 165185029Spjdstatic boolean_t 166185029Spjdzfs_is_bootfs(const char *name) 167185029Spjd{ 168185029Spjd spa_t *spa; 169185029Spjd boolean_t ret = B_FALSE; 170185029Spjd 171185029Spjd if (spa_open(name, &spa, FTAG) == 0) { 172185029Spjd if (spa->spa_bootfs) { 173185029Spjd objset_t *os; 174185029Spjd 175185029Spjd if (dmu_objset_open(name, DMU_OST_ZFS, 176185029Spjd DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 177185029Spjd ret = (dmu_objset_id(os) == spa->spa_bootfs); 178185029Spjd dmu_objset_close(os); 179185029Spjd } 180185029Spjd } 181185029Spjd spa_close(spa, FTAG); 182185029Spjd } 183185029Spjd return (ret); 184185029Spjd} 185185029Spjd 186185029Spjd/* 187185029Spjd * zfs_earlier_version 188185029Spjd * 189185029Spjd * Return non-zero if the spa version is less than requested version. 190185029Spjd */ 191185029Spjdstatic int 192185029Spjdzfs_earlier_version(const char *name, int version) 193185029Spjd{ 194185029Spjd spa_t *spa; 195185029Spjd 196185029Spjd if (spa_open(name, &spa, FTAG) == 0) { 197185029Spjd if (spa_version(spa) < version) { 198185029Spjd spa_close(spa, FTAG); 199185029Spjd return (1); 200185029Spjd } 201185029Spjd spa_close(spa, FTAG); 202185029Spjd } 203185029Spjd return (0); 204185029Spjd} 205185029Spjd 206185029Spjd/* 207185029Spjd * zpl_earlier_version 208185029Spjd * 209185029Spjd * Return TRUE if the ZPL version is less than requested version. 210185029Spjd */ 211185029Spjdstatic boolean_t 212185029Spjdzpl_earlier_version(const char *name, int version) 213185029Spjd{ 214185029Spjd objset_t *os; 215185029Spjd boolean_t rc = B_TRUE; 216185029Spjd 217185029Spjd if (dmu_objset_open(name, DMU_OST_ANY, 218185029Spjd DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 219185029Spjd uint64_t zplversion; 220185029Spjd 221185029Spjd if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 222185029Spjd rc = zplversion < version; 223185029Spjd dmu_objset_close(os); 224185029Spjd } 225185029Spjd return (rc); 226185029Spjd} 227185029Spjd 228185029Spjdstatic void 229185029Spjdzfs_log_history(zfs_cmd_t *zc) 230185029Spjd{ 231185029Spjd spa_t *spa; 232185029Spjd char *buf; 233185029Spjd 234185029Spjd if ((buf = history_str_get(zc)) == NULL) 235185029Spjd return; 236185029Spjd 237185029Spjd if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 238185029Spjd if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 239185029Spjd (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 240185029Spjd spa_close(spa, FTAG); 241185029Spjd } 242185029Spjd history_str_free(buf); 243185029Spjd} 244185029Spjd 245185029Spjd/* 246168404Spjd * Policy for top-level read operations (list pools). Requires no privileges, 247168404Spjd * and can be used in the local zone, as there is no associated dataset. 248168404Spjd */ 249168404Spjd/* ARGSUSED */ 250168404Spjdstatic int 251185029Spjdzfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 252168404Spjd{ 253168404Spjd return (0); 254168404Spjd} 255168404Spjd 256168404Spjd/* 257168404Spjd * Policy for dataset read operations (list children, get statistics). Requires 258168404Spjd * no privileges, but must be visible in the local zone. 259168404Spjd */ 260168404Spjd/* ARGSUSED */ 261168404Spjdstatic int 262185029Spjdzfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 263168404Spjd{ 264185029Spjd if (INGLOBALZONE(curthread) || 265185029Spjd zone_dataset_visible(zc->zc_name, NULL)) 266168404Spjd return (0); 267168404Spjd 268168404Spjd return (ENOENT); 269168404Spjd} 270168404Spjd 271168404Spjdstatic int 272168404Spjdzfs_dozonecheck(const char *dataset, cred_t *cr) 273168404Spjd{ 274168404Spjd uint64_t zoned; 275168404Spjd int writable = 1; 276168404Spjd 277168404Spjd /* 278168404Spjd * The dataset must be visible by this zone -- check this first 279168404Spjd * so they don't see EPERM on something they shouldn't know about. 280168404Spjd */ 281185029Spjd if (!INGLOBALZONE(curthread) && 282168404Spjd !zone_dataset_visible(dataset, &writable)) 283168404Spjd return (ENOENT); 284168404Spjd 285168404Spjd if (dsl_prop_get_integer(dataset, "jailed", &zoned, NULL)) 286168404Spjd return (ENOENT); 287168404Spjd 288185029Spjd if (INGLOBALZONE(curthread)) { 289168404Spjd /* 290168404Spjd * If the fs is zoned, only root can access it from the 291168404Spjd * global zone. 292168404Spjd */ 293168404Spjd if (secpolicy_zfs(cr) && zoned) 294168404Spjd return (EPERM); 295168404Spjd } else { 296168404Spjd /* 297168404Spjd * If we are in a local zone, the 'zoned' property must be set. 298168404Spjd */ 299168404Spjd if (!zoned) 300168404Spjd return (EPERM); 301168404Spjd 302168404Spjd /* must be writable by this zone */ 303168404Spjd if (!writable) 304168404Spjd return (EPERM); 305168404Spjd } 306168404Spjd return (0); 307168404Spjd} 308168404Spjd 309168404Spjdint 310185029Spjdzfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 311168404Spjd{ 312168404Spjd int error; 313168404Spjd 314185029Spjd error = zfs_dozonecheck(name, cr); 315185029Spjd if (error == 0) { 316185029Spjd error = secpolicy_zfs(cr); 317185029Spjd if (error) 318185029Spjd error = dsl_deleg_access(name, perm, cr); 319185029Spjd } 320185029Spjd return (error); 321185029Spjd} 322185029Spjd 323185029Spjdstatic int 324185029Spjdzfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) 325185029Spjd{ 326185029Spjd /* 327185029Spjd * Check permissions for special properties. 328185029Spjd */ 329185029Spjd switch (prop) { 330185029Spjd case ZFS_PROP_ZONED: 331185029Spjd /* 332185029Spjd * Disallow setting of 'zoned' from within a local zone. 333185029Spjd */ 334185029Spjd if (!INGLOBALZONE(curthread)) 335185029Spjd return (EPERM); 336185029Spjd break; 337185029Spjd 338185029Spjd case ZFS_PROP_QUOTA: 339185029Spjd if (!INGLOBALZONE(curthread)) { 340185029Spjd uint64_t zoned; 341185029Spjd char setpoint[MAXNAMELEN]; 342185029Spjd /* 343185029Spjd * Unprivileged users are allowed to modify the 344185029Spjd * quota on things *under* (ie. contained by) 345185029Spjd * the thing they own. 346185029Spjd */ 347185029Spjd if (dsl_prop_get_integer(name, "zoned", &zoned, 348185029Spjd setpoint)) 349185029Spjd return (EPERM); 350185029Spjd if (!zoned || strlen(name) <= strlen(setpoint)) 351185029Spjd return (EPERM); 352185029Spjd } 353185029Spjd break; 354185029Spjd } 355185029Spjd 356185029Spjd return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); 357185029Spjd} 358185029Spjd 359185029Spjdint 360185029Spjdzfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 361185029Spjd{ 362185029Spjd int error; 363185029Spjd 364185029Spjd error = zfs_dozonecheck(zc->zc_name, cr); 365185029Spjd if (error) 366168404Spjd return (error); 367168404Spjd 368185029Spjd /* 369185029Spjd * permission to set permissions will be evaluated later in 370185029Spjd * dsl_deleg_can_allow() 371185029Spjd */ 372185029Spjd return (0); 373168404Spjd} 374168404Spjd 375185029Spjdint 376185029Spjdzfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 377185029Spjd{ 378185029Spjd int error; 379185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 380185029Spjd ZFS_DELEG_PERM_ROLLBACK, cr); 381185029Spjd if (error == 0) 382185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 383185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 384185029Spjd return (error); 385185029Spjd} 386185029Spjd 387185029Spjdint 388185029Spjdzfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 389185029Spjd{ 390185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 391185029Spjd ZFS_DELEG_PERM_SEND, cr)); 392185029Spjd} 393185029Spjd 394185029Spjdint 395185029Spjdzfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 396185029Spjd{ 397185029Spjd if (!INGLOBALZONE(curthread)) 398185029Spjd return (EPERM); 399185029Spjd 400185029Spjd if (secpolicy_nfs(cr) == 0) { 401185029Spjd return (0); 402185029Spjd } else { 403185029Spjd vnode_t *vp; 404185029Spjd int error; 405185029Spjd 406185029Spjd if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 407185029Spjd NO_FOLLOW, NULL, &vp)) != 0) 408185029Spjd return (error); 409185029Spjd 410185029Spjd /* Now make sure mntpnt and dataset are ZFS */ 411185029Spjd 412185029Spjd if (strcmp(vp->v_vfsp->mnt_stat.f_fstypename, "zfs") != 0 || 413185029Spjd (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 414185029Spjd zc->zc_name) != 0)) { 415185029Spjd VN_RELE(vp); 416185029Spjd return (EPERM); 417185029Spjd } 418185029Spjd 419185029Spjd VN_RELE(vp); 420185029Spjd return (dsl_deleg_access(zc->zc_name, 421185029Spjd ZFS_DELEG_PERM_SHARE, cr)); 422185029Spjd } 423185029Spjd} 424185029Spjd 425168404Spjdstatic int 426185029Spjdzfs_get_parent(const char *datasetname, char *parent, int parentsize) 427168404Spjd{ 428168404Spjd char *cp; 429168404Spjd 430168404Spjd /* 431168404Spjd * Remove the @bla or /bla from the end of the name to get the parent. 432168404Spjd */ 433185029Spjd (void) strncpy(parent, datasetname, parentsize); 434185029Spjd cp = strrchr(parent, '@'); 435168404Spjd if (cp != NULL) { 436168404Spjd cp[0] = '\0'; 437168404Spjd } else { 438185029Spjd cp = strrchr(parent, '/'); 439168404Spjd if (cp == NULL) 440168404Spjd return (ENOENT); 441168404Spjd cp[0] = '\0'; 442185029Spjd } 443168404Spjd 444185029Spjd return (0); 445185029Spjd} 446185029Spjd 447185029Spjdint 448185029Spjdzfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 449185029Spjd{ 450185029Spjd int error; 451185029Spjd 452185029Spjd if ((error = zfs_secpolicy_write_perms(name, 453185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 454185029Spjd return (error); 455185029Spjd 456185029Spjd return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 457185029Spjd} 458185029Spjd 459185029Spjdstatic int 460185029Spjdzfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 461185029Spjd{ 462185029Spjd return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 463185029Spjd} 464185029Spjd 465185029Spjd/* 466185029Spjd * Must have sys_config privilege to check the iscsi permission 467185029Spjd */ 468185029Spjd/* ARGSUSED */ 469185029Spjdstatic int 470185029Spjdzfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) 471185029Spjd{ 472185029Spjd return (secpolicy_zfs(cr)); 473185029Spjd} 474185029Spjd 475185029Spjdint 476185029Spjdzfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 477185029Spjd{ 478185029Spjd char parentname[MAXNAMELEN]; 479185029Spjd int error; 480185029Spjd 481185029Spjd if ((error = zfs_secpolicy_write_perms(from, 482185029Spjd ZFS_DELEG_PERM_RENAME, cr)) != 0) 483185029Spjd return (error); 484185029Spjd 485185029Spjd if ((error = zfs_secpolicy_write_perms(from, 486185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 487185029Spjd return (error); 488185029Spjd 489185029Spjd if ((error = zfs_get_parent(to, parentname, 490185029Spjd sizeof (parentname))) != 0) 491185029Spjd return (error); 492185029Spjd 493185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 494185029Spjd ZFS_DELEG_PERM_CREATE, cr)) != 0) 495185029Spjd return (error); 496185029Spjd 497185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 498185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 499185029Spjd return (error); 500185029Spjd 501185029Spjd return (error); 502185029Spjd} 503185029Spjd 504185029Spjdstatic int 505185029Spjdzfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 506185029Spjd{ 507185029Spjd return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 508185029Spjd} 509185029Spjd 510185029Spjdstatic int 511185029Spjdzfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 512185029Spjd{ 513185029Spjd char parentname[MAXNAMELEN]; 514185029Spjd objset_t *clone; 515185029Spjd int error; 516185029Spjd 517185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 518185029Spjd ZFS_DELEG_PERM_PROMOTE, cr); 519185029Spjd if (error) 520185029Spjd return (error); 521185029Spjd 522185029Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 523185029Spjd DS_MODE_USER | DS_MODE_READONLY, &clone); 524185029Spjd 525185029Spjd if (error == 0) { 526185029Spjd dsl_dataset_t *pclone = NULL; 527185029Spjd dsl_dir_t *dd; 528185029Spjd dd = clone->os->os_dsl_dataset->ds_dir; 529185029Spjd 530185029Spjd rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 531185029Spjd error = dsl_dataset_hold_obj(dd->dd_pool, 532185029Spjd dd->dd_phys->dd_origin_obj, FTAG, &pclone); 533185029Spjd rw_exit(&dd->dd_pool->dp_config_rwlock); 534185029Spjd if (error) { 535185029Spjd dmu_objset_close(clone); 536185029Spjd return (error); 537185029Spjd } 538185029Spjd 539185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 540185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 541185029Spjd 542185029Spjd dsl_dataset_name(pclone, parentname); 543185029Spjd dmu_objset_close(clone); 544185029Spjd dsl_dataset_rele(pclone, FTAG); 545185029Spjd if (error == 0) 546185029Spjd error = zfs_secpolicy_write_perms(parentname, 547185029Spjd ZFS_DELEG_PERM_PROMOTE, cr); 548168404Spjd } 549185029Spjd return (error); 550185029Spjd} 551168404Spjd 552185029Spjdstatic int 553185029Spjdzfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 554185029Spjd{ 555185029Spjd int error; 556185029Spjd 557185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 558185029Spjd ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 559185029Spjd return (error); 560185029Spjd 561185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 562185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 563185029Spjd return (error); 564185029Spjd 565185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 566185029Spjd ZFS_DELEG_PERM_CREATE, cr)); 567168404Spjd} 568168404Spjd 569185029Spjdint 570185029Spjdzfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 571185029Spjd{ 572185029Spjd int error; 573185029Spjd 574185029Spjd if ((error = zfs_secpolicy_write_perms(name, 575185029Spjd ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) 576185029Spjd return (error); 577185029Spjd 578185029Spjd error = zfs_secpolicy_write_perms(name, 579185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 580185029Spjd 581185029Spjd return (error); 582185029Spjd} 583185029Spjd 584185029Spjdstatic int 585185029Spjdzfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 586185029Spjd{ 587185029Spjd 588185029Spjd return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 589185029Spjd} 590185029Spjd 591185029Spjdstatic int 592185029Spjdzfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 593185029Spjd{ 594185029Spjd char parentname[MAXNAMELEN]; 595185029Spjd int error; 596185029Spjd 597185029Spjd if ((error = zfs_get_parent(zc->zc_name, parentname, 598185029Spjd sizeof (parentname))) != 0) 599185029Spjd return (error); 600185029Spjd 601185029Spjd if (zc->zc_value[0] != '\0') { 602185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_value, 603185029Spjd ZFS_DELEG_PERM_CLONE, cr)) != 0) 604185029Spjd return (error); 605185029Spjd } 606185029Spjd 607185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 608185029Spjd ZFS_DELEG_PERM_CREATE, cr)) != 0) 609185029Spjd return (error); 610185029Spjd 611185029Spjd error = zfs_secpolicy_write_perms(parentname, 612185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 613185029Spjd 614185029Spjd return (error); 615185029Spjd} 616185029Spjd 617185029Spjdstatic int 618185029Spjdzfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 619185029Spjd{ 620185029Spjd int error; 621185029Spjd 622185029Spjd error = secpolicy_fs_unmount(cr, NULL); 623185029Spjd if (error) { 624185029Spjd error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 625185029Spjd } 626185029Spjd return (error); 627185029Spjd} 628185029Spjd 629168404Spjd/* 630168404Spjd * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 631168404Spjd * SYS_CONFIG privilege, which is not available in a local zone. 632168404Spjd */ 633168404Spjd/* ARGSUSED */ 634168404Spjdstatic int 635185029Spjdzfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 636168404Spjd{ 637168404Spjd if (secpolicy_sys_config(cr, B_FALSE) != 0) 638168404Spjd return (EPERM); 639168404Spjd 640168404Spjd return (0); 641168404Spjd} 642168404Spjd 643168404Spjd/* 644185029Spjd * Just like zfs_secpolicy_config, except that we will check for 645185029Spjd * mount permission on the dataset for permission to create/remove 646185029Spjd * the minor nodes. 647185029Spjd */ 648185029Spjdstatic int 649185029Spjdzfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) 650185029Spjd{ 651185029Spjd if (secpolicy_sys_config(cr, B_FALSE) != 0) { 652185029Spjd return (dsl_deleg_access(zc->zc_name, 653185029Spjd ZFS_DELEG_PERM_MOUNT, cr)); 654185029Spjd } 655185029Spjd 656185029Spjd return (0); 657185029Spjd} 658185029Spjd 659185029Spjd/* 660168404Spjd * Policy for fault injection. Requires all privileges. 661168404Spjd */ 662168404Spjd/* ARGSUSED */ 663168404Spjdstatic int 664185029Spjdzfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 665168404Spjd{ 666168404Spjd return (secpolicy_zinject(cr)); 667168404Spjd} 668168404Spjd 669185029Spjdstatic int 670185029Spjdzfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 671185029Spjd{ 672185029Spjd zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 673185029Spjd 674185029Spjd if (prop == ZPROP_INVAL) { 675185029Spjd if (!zfs_prop_user(zc->zc_value)) 676185029Spjd return (EINVAL); 677185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 678185029Spjd ZFS_DELEG_PERM_USERPROP, cr)); 679185029Spjd } else { 680185029Spjd if (!zfs_prop_inheritable(prop)) 681185029Spjd return (EINVAL); 682185029Spjd return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); 683185029Spjd } 684185029Spjd} 685185029Spjd 686168404Spjd/* 687168404Spjd * Policy for dataset backup operations (sendbackup). 688168404Spjd * Requires SYS_MOUNT privilege, and must be writable in the local zone. 689168404Spjd */ 690168404Spjdstatic int 691168404Spjdzfs_secpolicy_operator(const char *dataset, cred_t *cr) 692168404Spjd{ 693168404Spjd int writable = 1; 694168404Spjd 695185029Spjd if (!INGLOBALZONE(curthread) && !zone_dataset_visible(dataset, &writable)) 696168404Spjd return (ENOENT); 697168404Spjd if (secpolicy_zfs(cr) != 0 && !groupmember(GID_OPERATOR, cr)) 698168404Spjd return (EPERM); 699168404Spjd return (0); 700168404Spjd} 701168404Spjd 702168404Spjd/* 703168404Spjd * Returns the nvlist as specified by the user in the zfs_cmd_t. 704168404Spjd */ 705168404Spjdstatic int 706185029Spjdget_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) 707168404Spjd{ 708168404Spjd char *packed; 709168404Spjd int error; 710185029Spjd nvlist_t *list = NULL; 711168404Spjd 712168404Spjd /* 713168404Spjd * Read in and unpack the user-supplied nvlist. 714168404Spjd */ 715185029Spjd if (size == 0) 716168404Spjd return (EINVAL); 717168404Spjd 718168404Spjd packed = kmem_alloc(size, KM_SLEEP); 719168404Spjd 720185029Spjd if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { 721168404Spjd kmem_free(packed, size); 722168404Spjd return (error); 723168404Spjd } 724168404Spjd 725185029Spjd if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 726168404Spjd kmem_free(packed, size); 727168404Spjd return (error); 728168404Spjd } 729168404Spjd 730168404Spjd kmem_free(packed, size); 731168404Spjd 732185029Spjd *nvp = list; 733168404Spjd return (0); 734168404Spjd} 735168404Spjd 736168404Spjdstatic int 737168404Spjdput_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 738168404Spjd{ 739168404Spjd char *packed = NULL; 740168404Spjd size_t size; 741168404Spjd int error; 742168404Spjd 743168404Spjd VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 744168404Spjd 745168404Spjd if (size > zc->zc_nvlist_dst_size) { 746168404Spjd /* 747168404Spjd * Solaris returns ENOMEM here, because even if an error is 748168404Spjd * returned from an ioctl(2), new zc_nvlist_dst_size will be 749168404Spjd * passed to the userland. This is not the case for FreeBSD. 750168404Spjd * We need to return 0, so the kernel will copy the 751168404Spjd * zc_nvlist_dst_size back and the userland can discover that a 752168404Spjd * bigger buffer is needed. 753168404Spjd */ 754168404Spjd error = 0; 755168404Spjd } else { 756185029Spjd packed = kmem_alloc(size, KM_SLEEP); 757168404Spjd VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 758168404Spjd KM_SLEEP) == 0); 759168404Spjd error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 760168404Spjd size); 761168404Spjd kmem_free(packed, size); 762168404Spjd } 763168404Spjd 764168404Spjd zc->zc_nvlist_dst_size = size; 765168404Spjd return (error); 766168404Spjd} 767168404Spjd 768168404Spjdstatic int 769168404Spjdzfs_ioc_pool_create(zfs_cmd_t *zc) 770168404Spjd{ 771168404Spjd int error; 772185029Spjd nvlist_t *config, *props = NULL; 773185029Spjd nvlist_t *rootprops = NULL; 774185029Spjd nvlist_t *zplprops = NULL; 775185029Spjd char *buf; 776168404Spjd 777185029Spjd if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 778185029Spjd &config)) 779168404Spjd return (error); 780168404Spjd 781185029Spjd if (zc->zc_nvlist_src_size != 0 && (error = 782185029Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 783185029Spjd nvlist_free(config); 784185029Spjd return (error); 785185029Spjd } 786168404Spjd 787185029Spjd if (props) { 788185029Spjd nvlist_t *nvl = NULL; 789185029Spjd uint64_t version = SPA_VERSION; 790185029Spjd 791185029Spjd (void) nvlist_lookup_uint64(props, 792185029Spjd zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 793185029Spjd if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 794185029Spjd error = EINVAL; 795185029Spjd goto pool_props_bad; 796185029Spjd } 797185029Spjd (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 798185029Spjd if (nvl) { 799185029Spjd error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 800185029Spjd if (error != 0) { 801185029Spjd nvlist_free(config); 802185029Spjd nvlist_free(props); 803185029Spjd return (error); 804185029Spjd } 805185029Spjd (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 806185029Spjd } 807185029Spjd VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 808185029Spjd error = zfs_fill_zplprops_root(version, rootprops, 809185029Spjd zplprops, NULL); 810185029Spjd if (error) 811185029Spjd goto pool_props_bad; 812185029Spjd } 813185029Spjd 814185029Spjd buf = history_str_get(zc); 815185029Spjd 816185029Spjd error = spa_create(zc->zc_name, config, props, buf, zplprops); 817185029Spjd 818185029Spjd /* 819185029Spjd * Set the remaining root properties 820185029Spjd */ 821185029Spjd if (!error && 822185029Spjd (error = zfs_set_prop_nvlist(zc->zc_name, rootprops)) != 0) 823185029Spjd (void) spa_destroy(zc->zc_name); 824185029Spjd 825185029Spjd if (buf != NULL) 826185029Spjd history_str_free(buf); 827185029Spjd 828185029Spjdpool_props_bad: 829185029Spjd nvlist_free(rootprops); 830185029Spjd nvlist_free(zplprops); 831168404Spjd nvlist_free(config); 832185029Spjd nvlist_free(props); 833168404Spjd 834168404Spjd return (error); 835168404Spjd} 836168404Spjd 837168404Spjdstatic int 838168404Spjdzfs_ioc_pool_destroy(zfs_cmd_t *zc) 839168404Spjd{ 840185029Spjd int error; 841185029Spjd zfs_log_history(zc); 842185029Spjd error = spa_destroy(zc->zc_name); 843185029Spjd return (error); 844168404Spjd} 845168404Spjd 846168404Spjdstatic int 847168404Spjdzfs_ioc_pool_import(zfs_cmd_t *zc) 848168404Spjd{ 849168404Spjd int error; 850185029Spjd nvlist_t *config, *props = NULL; 851168404Spjd uint64_t guid; 852168404Spjd 853185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 854185029Spjd &config)) != 0) 855168404Spjd return (error); 856168404Spjd 857185029Spjd if (zc->zc_nvlist_src_size != 0 && (error = 858185029Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { 859185029Spjd nvlist_free(config); 860185029Spjd return (error); 861185029Spjd } 862185029Spjd 863168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 864168404Spjd guid != zc->zc_guid) 865168404Spjd error = EINVAL; 866185029Spjd else if (zc->zc_cookie) 867185029Spjd error = spa_import_faulted(zc->zc_name, config, 868185029Spjd props); 869168404Spjd else 870185029Spjd error = spa_import(zc->zc_name, config, props); 871168404Spjd 872168404Spjd nvlist_free(config); 873168404Spjd 874185029Spjd if (props) 875185029Spjd nvlist_free(props); 876185029Spjd 877168404Spjd return (error); 878168404Spjd} 879168404Spjd 880168404Spjdstatic int 881168404Spjdzfs_ioc_pool_export(zfs_cmd_t *zc) 882168404Spjd{ 883185029Spjd int error; 884185029Spjd boolean_t force = (boolean_t)zc->zc_cookie; 885185029Spjd 886185029Spjd zfs_log_history(zc); 887185029Spjd error = spa_export(zc->zc_name, NULL, force); 888185029Spjd return (error); 889168404Spjd} 890168404Spjd 891168404Spjdstatic int 892168404Spjdzfs_ioc_pool_configs(zfs_cmd_t *zc) 893168404Spjd{ 894168404Spjd nvlist_t *configs; 895168404Spjd int error; 896168404Spjd 897168404Spjd if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 898168404Spjd return (EEXIST); 899168404Spjd 900168404Spjd error = put_nvlist(zc, configs); 901168404Spjd 902168404Spjd nvlist_free(configs); 903168404Spjd 904168404Spjd return (error); 905168404Spjd} 906168404Spjd 907168404Spjdstatic int 908168404Spjdzfs_ioc_pool_stats(zfs_cmd_t *zc) 909168404Spjd{ 910168404Spjd nvlist_t *config; 911168404Spjd int error; 912168404Spjd int ret = 0; 913168404Spjd 914168404Spjd error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 915168404Spjd sizeof (zc->zc_value)); 916168404Spjd 917168404Spjd if (config != NULL) { 918168404Spjd ret = put_nvlist(zc, config); 919168404Spjd nvlist_free(config); 920168404Spjd 921168404Spjd /* 922168404Spjd * The config may be present even if 'error' is non-zero. 923168404Spjd * In this case we return success, and preserve the real errno 924168404Spjd * in 'zc_cookie'. 925168404Spjd */ 926168404Spjd zc->zc_cookie = error; 927168404Spjd } else { 928168404Spjd ret = error; 929168404Spjd } 930168404Spjd 931168404Spjd return (ret); 932168404Spjd} 933168404Spjd 934168404Spjd/* 935168404Spjd * Try to import the given pool, returning pool stats as appropriate so that 936168404Spjd * user land knows which devices are available and overall pool health. 937168404Spjd */ 938168404Spjdstatic int 939168404Spjdzfs_ioc_pool_tryimport(zfs_cmd_t *zc) 940168404Spjd{ 941168404Spjd nvlist_t *tryconfig, *config; 942168404Spjd int error; 943168404Spjd 944185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 945185029Spjd &tryconfig)) != 0) 946168404Spjd return (error); 947168404Spjd 948168404Spjd config = spa_tryimport(tryconfig); 949168404Spjd 950168404Spjd nvlist_free(tryconfig); 951168404Spjd 952168404Spjd if (config == NULL) 953168404Spjd return (EINVAL); 954168404Spjd 955168404Spjd error = put_nvlist(zc, config); 956168404Spjd nvlist_free(config); 957168404Spjd 958168404Spjd return (error); 959168404Spjd} 960168404Spjd 961168404Spjdstatic int 962168404Spjdzfs_ioc_pool_scrub(zfs_cmd_t *zc) 963168404Spjd{ 964168404Spjd spa_t *spa; 965168404Spjd int error; 966168404Spjd 967168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 968168404Spjd return (error); 969168404Spjd 970185029Spjd error = spa_scrub(spa, zc->zc_cookie); 971168404Spjd 972168404Spjd spa_close(spa, FTAG); 973168404Spjd 974168404Spjd return (error); 975168404Spjd} 976168404Spjd 977168404Spjdstatic int 978168404Spjdzfs_ioc_pool_freeze(zfs_cmd_t *zc) 979168404Spjd{ 980168404Spjd spa_t *spa; 981168404Spjd int error; 982168404Spjd 983168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 984168404Spjd if (error == 0) { 985168404Spjd spa_freeze(spa); 986168404Spjd spa_close(spa, FTAG); 987168404Spjd } 988168404Spjd return (error); 989168404Spjd} 990168404Spjd 991168404Spjdstatic int 992168404Spjdzfs_ioc_pool_upgrade(zfs_cmd_t *zc) 993168404Spjd{ 994168404Spjd spa_t *spa; 995168404Spjd int error; 996168404Spjd 997168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 998168404Spjd return (error); 999168404Spjd 1000185029Spjd if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 1001185029Spjd spa_close(spa, FTAG); 1002185029Spjd return (EINVAL); 1003185029Spjd } 1004168404Spjd 1005185029Spjd spa_upgrade(spa, zc->zc_cookie); 1006168404Spjd spa_close(spa, FTAG); 1007168404Spjd 1008168404Spjd return (error); 1009168404Spjd} 1010168404Spjd 1011168404Spjdstatic int 1012168404Spjdzfs_ioc_pool_get_history(zfs_cmd_t *zc) 1013168404Spjd{ 1014168404Spjd spa_t *spa; 1015168404Spjd char *hist_buf; 1016168404Spjd uint64_t size; 1017168404Spjd int error; 1018168404Spjd 1019168404Spjd if ((size = zc->zc_history_len) == 0) 1020168404Spjd return (EINVAL); 1021168404Spjd 1022168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1023168404Spjd return (error); 1024168404Spjd 1025185029Spjd if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1026168404Spjd spa_close(spa, FTAG); 1027168404Spjd return (ENOTSUP); 1028168404Spjd } 1029168404Spjd 1030168404Spjd hist_buf = kmem_alloc(size, KM_SLEEP); 1031168404Spjd if ((error = spa_history_get(spa, &zc->zc_history_offset, 1032168404Spjd &zc->zc_history_len, hist_buf)) == 0) { 1033185029Spjd error = xcopyout(hist_buf, 1034185029Spjd (char *)(uintptr_t)zc->zc_history, 1035168404Spjd zc->zc_history_len); 1036168404Spjd } 1037168404Spjd 1038168404Spjd spa_close(spa, FTAG); 1039168404Spjd kmem_free(hist_buf, size); 1040168404Spjd return (error); 1041168404Spjd} 1042168404Spjd 1043168404Spjdstatic int 1044168404Spjdzfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 1045168404Spjd{ 1046168404Spjd int error; 1047168404Spjd 1048168404Spjd if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 1049168404Spjd return (error); 1050168404Spjd 1051168404Spjd return (0); 1052168404Spjd} 1053168404Spjd 1054168404Spjdstatic int 1055168404Spjdzfs_ioc_obj_to_path(zfs_cmd_t *zc) 1056168404Spjd{ 1057168404Spjd objset_t *osp; 1058168404Spjd int error; 1059168404Spjd 1060168404Spjd if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 1061185029Spjd DS_MODE_USER | DS_MODE_READONLY, &osp)) != 0) 1062168404Spjd return (error); 1063168404Spjd error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 1064168404Spjd sizeof (zc->zc_value)); 1065168404Spjd dmu_objset_close(osp); 1066168404Spjd 1067168404Spjd return (error); 1068168404Spjd} 1069168404Spjd 1070168404Spjdstatic int 1071168404Spjdzfs_ioc_vdev_add(zfs_cmd_t *zc) 1072168404Spjd{ 1073168404Spjd spa_t *spa; 1074168404Spjd int error; 1075185029Spjd nvlist_t *config, **l2cache, **spares; 1076185029Spjd uint_t nl2cache = 0, nspares = 0; 1077168404Spjd 1078168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1079168404Spjd if (error != 0) 1080168404Spjd return (error); 1081168404Spjd 1082185029Spjd error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1083185029Spjd &config); 1084185029Spjd (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1085185029Spjd &l2cache, &nl2cache); 1086185029Spjd 1087185029Spjd (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1088185029Spjd &spares, &nspares); 1089185029Spjd 1090168404Spjd /* 1091168404Spjd * A root pool with concatenated devices is not supported. 1092185029Spjd * Thus, can not add a device to a root pool. 1093185029Spjd * 1094185029Spjd * Intent log device can not be added to a rootpool because 1095185029Spjd * during mountroot, zil is replayed, a seperated log device 1096185029Spjd * can not be accessed during the mountroot time. 1097185029Spjd * 1098185029Spjd * l2cache and spare devices are ok to be added to a rootpool. 1099168404Spjd */ 1100185029Spjd if (spa->spa_bootfs != 0 && nl2cache == 0 && nspares == 0) { 1101168404Spjd spa_close(spa, FTAG); 1102168404Spjd return (EDOM); 1103168404Spjd } 1104168404Spjd 1105185029Spjd if (error == 0) { 1106168404Spjd error = spa_vdev_add(spa, config); 1107168404Spjd nvlist_free(config); 1108168404Spjd } 1109168404Spjd spa_close(spa, FTAG); 1110168404Spjd return (error); 1111168404Spjd} 1112168404Spjd 1113168404Spjdstatic int 1114168404Spjdzfs_ioc_vdev_remove(zfs_cmd_t *zc) 1115168404Spjd{ 1116168404Spjd spa_t *spa; 1117168404Spjd int error; 1118168404Spjd 1119168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1120168404Spjd if (error != 0) 1121168404Spjd return (error); 1122168404Spjd error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 1123168404Spjd spa_close(spa, FTAG); 1124168404Spjd return (error); 1125168404Spjd} 1126168404Spjd 1127168404Spjdstatic int 1128185029Spjdzfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1129168404Spjd{ 1130168404Spjd spa_t *spa; 1131168404Spjd int error; 1132185029Spjd vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1133168404Spjd 1134168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1135168404Spjd return (error); 1136185029Spjd switch (zc->zc_cookie) { 1137185029Spjd case VDEV_STATE_ONLINE: 1138185029Spjd error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 1139185029Spjd break; 1140168404Spjd 1141185029Spjd case VDEV_STATE_OFFLINE: 1142185029Spjd error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 1143185029Spjd break; 1144168404Spjd 1145185029Spjd case VDEV_STATE_FAULTED: 1146185029Spjd error = vdev_fault(spa, zc->zc_guid); 1147185029Spjd break; 1148185029Spjd 1149185029Spjd case VDEV_STATE_DEGRADED: 1150185029Spjd error = vdev_degrade(spa, zc->zc_guid); 1151185029Spjd break; 1152185029Spjd 1153185029Spjd default: 1154185029Spjd error = EINVAL; 1155185029Spjd } 1156185029Spjd zc->zc_cookie = newstate; 1157168404Spjd spa_close(spa, FTAG); 1158168404Spjd return (error); 1159168404Spjd} 1160168404Spjd 1161168404Spjdstatic int 1162168404Spjdzfs_ioc_vdev_attach(zfs_cmd_t *zc) 1163168404Spjd{ 1164168404Spjd spa_t *spa; 1165168404Spjd int replacing = zc->zc_cookie; 1166168404Spjd nvlist_t *config; 1167168404Spjd int error; 1168168404Spjd 1169168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1170168404Spjd return (error); 1171168404Spjd 1172185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1173185029Spjd &config)) == 0) { 1174168404Spjd error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1175168404Spjd nvlist_free(config); 1176168404Spjd } 1177168404Spjd 1178168404Spjd spa_close(spa, FTAG); 1179168404Spjd return (error); 1180168404Spjd} 1181168404Spjd 1182168404Spjdstatic int 1183168404Spjdzfs_ioc_vdev_detach(zfs_cmd_t *zc) 1184168404Spjd{ 1185168404Spjd spa_t *spa; 1186168404Spjd int error; 1187168404Spjd 1188168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1189168404Spjd return (error); 1190168404Spjd 1191168404Spjd error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 1192168404Spjd 1193168404Spjd spa_close(spa, FTAG); 1194168404Spjd return (error); 1195168404Spjd} 1196168404Spjd 1197168404Spjdstatic int 1198168404Spjdzfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1199168404Spjd{ 1200168404Spjd spa_t *spa; 1201168404Spjd char *path = zc->zc_value; 1202168404Spjd uint64_t guid = zc->zc_guid; 1203168404Spjd int error; 1204168404Spjd 1205168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1206168404Spjd if (error != 0) 1207168404Spjd return (error); 1208168404Spjd 1209168404Spjd error = spa_vdev_setpath(spa, guid, path); 1210168404Spjd spa_close(spa, FTAG); 1211168404Spjd return (error); 1212168404Spjd} 1213168404Spjd 1214185029Spjd/* 1215185029Spjd * inputs: 1216185029Spjd * zc_name name of filesystem 1217185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1218185029Spjd * 1219185029Spjd * outputs: 1220185029Spjd * zc_objset_stats stats 1221185029Spjd * zc_nvlist_dst property nvlist 1222185029Spjd * zc_nvlist_dst_size size of property nvlist 1223185029Spjd */ 1224168404Spjdstatic int 1225168404Spjdzfs_ioc_objset_stats(zfs_cmd_t *zc) 1226168404Spjd{ 1227168404Spjd objset_t *os = NULL; 1228168404Spjd int error; 1229168404Spjd nvlist_t *nv; 1230168404Spjd 1231185029Spjd if (error = dmu_objset_open(zc->zc_name, 1232185029Spjd DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1233168404Spjd return (error); 1234168404Spjd 1235168404Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1236168404Spjd 1237168404Spjd if (zc->zc_nvlist_dst != 0 && 1238185029Spjd (error = dsl_prop_get_all(os, &nv, FALSE)) == 0) { 1239168404Spjd dmu_objset_stats(os, nv); 1240168404Spjd /* 1241168404Spjd * NB: zvol_get_stats() will read the objset contents, 1242168404Spjd * which we aren't supposed to do with a 1243185029Spjd * DS_MODE_USER hold, because it could be 1244168404Spjd * inconsistent. So this is a bit of a workaround... 1245168404Spjd */ 1246185029Spjd if (!zc->zc_objset_stats.dds_inconsistent) { 1247185029Spjd if (dmu_objset_type(os) == DMU_OST_ZVOL) 1248185029Spjd VERIFY(zvol_get_stats(os, nv) == 0); 1249185029Spjd } 1250168404Spjd error = put_nvlist(zc, nv); 1251168404Spjd nvlist_free(nv); 1252168404Spjd } 1253168404Spjd 1254168404Spjd dmu_objset_close(os); 1255168404Spjd if (error == ENOMEM) 1256168404Spjd error = 0; 1257168404Spjd return (error); 1258168404Spjd} 1259168404Spjd 1260168404Spjdstatic int 1261185029Spjdnvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1262185029Spjd{ 1263185029Spjd uint64_t value; 1264185029Spjd int error; 1265185029Spjd 1266185029Spjd /* 1267185029Spjd * zfs_get_zplprop() will either find a value or give us 1268185029Spjd * the default value (if there is one). 1269185029Spjd */ 1270185029Spjd if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1271185029Spjd return (error); 1272185029Spjd VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1273185029Spjd return (0); 1274185029Spjd} 1275185029Spjd 1276185029Spjd/* 1277185029Spjd * inputs: 1278185029Spjd * zc_name name of filesystem 1279185029Spjd * zc_nvlist_dst_size size of buffer for zpl property nvlist 1280185029Spjd * 1281185029Spjd * outputs: 1282185029Spjd * zc_nvlist_dst zpl property nvlist 1283185029Spjd * zc_nvlist_dst_size size of zpl property nvlist 1284185029Spjd */ 1285185029Spjdstatic int 1286185029Spjdzfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1287185029Spjd{ 1288185029Spjd objset_t *os; 1289185029Spjd int err; 1290185029Spjd 1291185029Spjd if (err = dmu_objset_open(zc->zc_name, 1292185029Spjd DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) 1293185029Spjd return (err); 1294185029Spjd 1295185029Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1296185029Spjd 1297185029Spjd /* 1298185029Spjd * NB: nvl_add_zplprop() will read the objset contents, 1299185029Spjd * which we aren't supposed to do with a DS_MODE_USER 1300185029Spjd * hold, because it could be inconsistent. 1301185029Spjd */ 1302185029Spjd if (zc->zc_nvlist_dst != 0 && 1303185029Spjd !zc->zc_objset_stats.dds_inconsistent && 1304185029Spjd dmu_objset_type(os) == DMU_OST_ZFS) { 1305185029Spjd nvlist_t *nv; 1306185029Spjd 1307185029Spjd VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1308185029Spjd if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1309185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1310185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1311185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1312185029Spjd err = put_nvlist(zc, nv); 1313185029Spjd nvlist_free(nv); 1314185029Spjd } else { 1315185029Spjd err = ENOENT; 1316185029Spjd } 1317185029Spjd dmu_objset_close(os); 1318185029Spjd return (err); 1319185029Spjd} 1320185029Spjd 1321185029Spjd/* 1322185029Spjd * inputs: 1323185029Spjd * zc_name name of filesystem 1324185029Spjd * zc_cookie zap cursor 1325185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1326185029Spjd * 1327185029Spjd * outputs: 1328185029Spjd * zc_name name of next filesystem 1329185029Spjd * zc_objset_stats stats 1330185029Spjd * zc_nvlist_dst property nvlist 1331185029Spjd * zc_nvlist_dst_size size of property nvlist 1332185029Spjd */ 1333185029Spjdstatic int 1334168404Spjdzfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1335168404Spjd{ 1336168404Spjd objset_t *os; 1337168404Spjd int error; 1338168404Spjd char *p; 1339168404Spjd 1340185029Spjd if (error = dmu_objset_open(zc->zc_name, 1341185029Spjd DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os)) { 1342168404Spjd if (error == ENOENT) 1343168404Spjd error = ESRCH; 1344168404Spjd return (error); 1345168404Spjd } 1346168404Spjd 1347168404Spjd p = strrchr(zc->zc_name, '/'); 1348168404Spjd if (p == NULL || p[1] != '\0') 1349168404Spjd (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1350168404Spjd p = zc->zc_name + strlen(zc->zc_name); 1351168404Spjd 1352207626Smm if (zc->zc_cookie == 0) { 1353207626Smm uint64_t cookie = 0; 1354207626Smm int len = sizeof (zc->zc_name) - (p - zc->zc_name); 1355207626Smm 1356207626Smm while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) 1357207626Smm dmu_objset_prefetch(p, NULL); 1358207626Smm } 1359207626Smm 1360168404Spjd do { 1361168404Spjd error = dmu_dir_list_next(os, 1362168404Spjd sizeof (zc->zc_name) - (p - zc->zc_name), p, 1363168404Spjd NULL, &zc->zc_cookie); 1364168404Spjd if (error == ENOENT) 1365168404Spjd error = ESRCH; 1366185029Spjd } while (error == 0 && !INGLOBALZONE(curthread) && 1367168404Spjd !zone_dataset_visible(zc->zc_name, NULL)); 1368185029Spjd dmu_objset_close(os); 1369168404Spjd 1370168404Spjd /* 1371168404Spjd * If it's a hidden dataset (ie. with a '$' in its name), don't 1372168404Spjd * try to get stats for it. Userland will skip over it. 1373168404Spjd */ 1374168404Spjd if (error == 0 && strchr(zc->zc_name, '$') == NULL) 1375168404Spjd error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1376168404Spjd 1377168404Spjd return (error); 1378168404Spjd} 1379168404Spjd 1380185029Spjd/* 1381185029Spjd * inputs: 1382185029Spjd * zc_name name of filesystem 1383185029Spjd * zc_cookie zap cursor 1384185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1385185029Spjd * 1386185029Spjd * outputs: 1387185029Spjd * zc_name name of next snapshot 1388185029Spjd * zc_objset_stats stats 1389185029Spjd * zc_nvlist_dst property nvlist 1390185029Spjd * zc_nvlist_dst_size size of property nvlist 1391185029Spjd */ 1392168404Spjdstatic int 1393168404Spjdzfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 1394168404Spjd{ 1395168404Spjd objset_t *os; 1396168404Spjd int error; 1397168404Spjd 1398207626Smm if (zc->zc_cookie == 0) 1399207626Smm dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 1400207626Smm NULL, DS_FIND_SNAPSHOTS); 1401185029Spjd error = dmu_objset_open(zc->zc_name, 1402185029Spjd DMU_OST_ANY, DS_MODE_USER | DS_MODE_READONLY, &os); 1403185029Spjd if (error) 1404185029Spjd return (error == ENOENT ? ESRCH : error); 1405168404Spjd 1406168404Spjd /* 1407168404Spjd * A dataset name of maximum length cannot have any snapshots, 1408168404Spjd * so exit immediately. 1409168404Spjd */ 1410168404Spjd if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 1411168404Spjd dmu_objset_close(os); 1412168404Spjd return (ESRCH); 1413168404Spjd } 1414168404Spjd 1415168404Spjd error = dmu_snapshot_list_next(os, 1416168404Spjd sizeof (zc->zc_name) - strlen(zc->zc_name), 1417185029Spjd zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie, NULL); 1418185029Spjd dmu_objset_close(os); 1419168404Spjd if (error == 0) 1420168404Spjd error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1421185029Spjd else if (error == ENOENT) 1422185029Spjd error = ESRCH; 1423168404Spjd 1424185029Spjd /* if we failed, undo the @ that we tacked on to zc_name */ 1425185029Spjd if (error) 1426185029Spjd *strchr(zc->zc_name, '@') = '\0'; 1427168404Spjd return (error); 1428168404Spjd} 1429168404Spjd 1430185029Spjdint 1431185029Spjdzfs_set_prop_nvlist(const char *name, nvlist_t *nvl) 1432168404Spjd{ 1433168404Spjd nvpair_t *elem; 1434168404Spjd int error; 1435168404Spjd uint64_t intval; 1436168404Spjd char *strval; 1437168404Spjd 1438185029Spjd /* 1439185029Spjd * First validate permission to set all of the properties 1440185029Spjd */ 1441168404Spjd elem = NULL; 1442168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1443185029Spjd const char *propname = nvpair_name(elem); 1444185029Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 1445168404Spjd 1446185029Spjd if (prop == ZPROP_INVAL) { 1447168404Spjd /* 1448168404Spjd * If this is a user-defined property, it must be a 1449168404Spjd * string, and there is no further validation to do. 1450168404Spjd */ 1451168404Spjd if (!zfs_prop_user(propname) || 1452168404Spjd nvpair_type(elem) != DATA_TYPE_STRING) 1453168404Spjd return (EINVAL); 1454168404Spjd 1455185029Spjd if (error = zfs_secpolicy_write_perms(name, 1456185029Spjd ZFS_DELEG_PERM_USERPROP, CRED())) 1457168404Spjd return (error); 1458185029Spjd continue; 1459168404Spjd } 1460168404Spjd 1461185029Spjd if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) 1462185029Spjd return (error); 1463185029Spjd 1464168404Spjd /* 1465185029Spjd * Check that this value is valid for this pool version 1466168404Spjd */ 1467168404Spjd switch (prop) { 1468168404Spjd case ZFS_PROP_COMPRESSION: 1469168404Spjd /* 1470168404Spjd * If the user specified gzip compression, make sure 1471168404Spjd * the SPA supports it. We ignore any errors here since 1472168404Spjd * we'll catch them later. 1473168404Spjd */ 1474168404Spjd if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1475185029Spjd nvpair_value_uint64(elem, &intval) == 0) { 1476185029Spjd if (intval >= ZIO_COMPRESS_GZIP_1 && 1477185029Spjd intval <= ZIO_COMPRESS_GZIP_9 && 1478185029Spjd zfs_earlier_version(name, 1479185029Spjd SPA_VERSION_GZIP_COMPRESSION)) 1480185029Spjd return (ENOTSUP); 1481168404Spjd 1482185029Spjd /* 1483185029Spjd * If this is a bootable dataset then 1484185029Spjd * verify that the compression algorithm 1485185029Spjd * is supported for booting. We must return 1486185029Spjd * something other than ENOTSUP since it 1487185029Spjd * implies a downrev pool version. 1488185029Spjd */ 1489185029Spjd if (zfs_is_bootfs(name) && 1490185029Spjd !BOOTFS_COMPRESS_VALID(intval)) 1491185029Spjd return (ERANGE); 1492168404Spjd } 1493168404Spjd break; 1494185029Spjd 1495185029Spjd case ZFS_PROP_COPIES: 1496185029Spjd if (zfs_earlier_version(name, 1497185029Spjd SPA_VERSION_DITTO_BLOCKS)) 1498185029Spjd return (ENOTSUP); 1499185029Spjd break; 1500185029Spjd 1501185029Spjd case ZFS_PROP_SHARESMB: 1502185029Spjd if (zpl_earlier_version(name, ZPL_VERSION_FUID)) 1503185029Spjd return (ENOTSUP); 1504185029Spjd break; 1505201143Sdelphij 1506201143Sdelphij case ZFS_PROP_ACLINHERIT: 1507201143Sdelphij if (nvpair_type(elem) == DATA_TYPE_UINT64 && 1508201143Sdelphij nvpair_value_uint64(elem, &intval) == 0) 1509201143Sdelphij if (intval == ZFS_ACL_PASSTHROUGH_X && 1510201143Sdelphij zfs_earlier_version(name, 1511201143Sdelphij SPA_VERSION_PASSTHROUGH_X)) 1512201143Sdelphij return (ENOTSUP); 1513168404Spjd } 1514185029Spjd } 1515168404Spjd 1516185029Spjd elem = NULL; 1517185029Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1518185029Spjd const char *propname = nvpair_name(elem); 1519185029Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 1520185029Spjd 1521185029Spjd if (prop == ZPROP_INVAL) { 1522185029Spjd VERIFY(nvpair_value_string(elem, &strval) == 0); 1523185029Spjd error = dsl_prop_set(name, propname, 1, 1524185029Spjd strlen(strval) + 1, strval); 1525185029Spjd if (error == 0) 1526185029Spjd continue; 1527185029Spjd else 1528185029Spjd return (error); 1529185029Spjd } 1530185029Spjd 1531168404Spjd switch (prop) { 1532168404Spjd case ZFS_PROP_QUOTA: 1533168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1534185029Spjd (error = dsl_dir_set_quota(name, intval)) != 0) 1535168404Spjd return (error); 1536168404Spjd break; 1537168404Spjd 1538185029Spjd case ZFS_PROP_REFQUOTA: 1539185029Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1540185029Spjd (error = dsl_dataset_set_quota(name, intval)) != 0) 1541185029Spjd return (error); 1542185029Spjd break; 1543185029Spjd 1544168404Spjd case ZFS_PROP_RESERVATION: 1545168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1546168404Spjd (error = dsl_dir_set_reservation(name, 1547168404Spjd intval)) != 0) 1548168404Spjd return (error); 1549168404Spjd break; 1550168404Spjd 1551185029Spjd case ZFS_PROP_REFRESERVATION: 1552168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1553185029Spjd (error = dsl_dataset_set_reservation(name, 1554168404Spjd intval)) != 0) 1555168404Spjd return (error); 1556168404Spjd break; 1557168404Spjd 1558185029Spjd case ZFS_PROP_VOLSIZE: 1559185029Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1560185029Spjd (error = zvol_set_volsize(name, 1561185029Spjd ddi_driver_major(zfs_dip), intval)) != 0) 1562185029Spjd return (error); 1563185029Spjd break; 1564185029Spjd 1565168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 1566168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1567185029Spjd (error = zvol_set_volblocksize(name, intval)) != 0) 1568168404Spjd return (error); 1569168404Spjd break; 1570168404Spjd 1571185029Spjd case ZFS_PROP_VERSION: 1572185029Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 1573185029Spjd (error = zfs_set_version(name, intval)) != 0) 1574185029Spjd return (error); 1575185029Spjd break; 1576185029Spjd 1577168404Spjd default: 1578168404Spjd if (nvpair_type(elem) == DATA_TYPE_STRING) { 1579168404Spjd if (zfs_prop_get_type(prop) != 1580185029Spjd PROP_TYPE_STRING) 1581168404Spjd return (EINVAL); 1582168404Spjd VERIFY(nvpair_value_string(elem, &strval) == 0); 1583168404Spjd if ((error = dsl_prop_set(name, 1584168404Spjd nvpair_name(elem), 1, strlen(strval) + 1, 1585168404Spjd strval)) != 0) 1586168404Spjd return (error); 1587168404Spjd } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1588168404Spjd const char *unused; 1589168404Spjd 1590168404Spjd VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1591168404Spjd 1592168404Spjd switch (zfs_prop_get_type(prop)) { 1593185029Spjd case PROP_TYPE_NUMBER: 1594168404Spjd break; 1595185029Spjd case PROP_TYPE_STRING: 1596168404Spjd return (EINVAL); 1597185029Spjd case PROP_TYPE_INDEX: 1598168404Spjd if (zfs_prop_index_to_string(prop, 1599168404Spjd intval, &unused) != 0) 1600168404Spjd return (EINVAL); 1601168404Spjd break; 1602168404Spjd default: 1603185029Spjd cmn_err(CE_PANIC, 1604185029Spjd "unknown property type"); 1605168404Spjd break; 1606168404Spjd } 1607168404Spjd 1608168404Spjd if ((error = dsl_prop_set(name, propname, 1609168404Spjd 8, 1, &intval)) != 0) 1610168404Spjd return (error); 1611168404Spjd } else { 1612168404Spjd return (EINVAL); 1613168404Spjd } 1614168404Spjd break; 1615168404Spjd } 1616168404Spjd } 1617168404Spjd 1618168404Spjd return (0); 1619168404Spjd} 1620168404Spjd 1621185029Spjd/* 1622185029Spjd * inputs: 1623185029Spjd * zc_name name of filesystem 1624185029Spjd * zc_value name of property to inherit 1625185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 1626185029Spjd * zc_cookie clear existing local props? 1627185029Spjd * 1628185029Spjd * outputs: none 1629185029Spjd */ 1630168404Spjdstatic int 1631168404Spjdzfs_ioc_set_prop(zfs_cmd_t *zc) 1632168404Spjd{ 1633168404Spjd nvlist_t *nvl; 1634168404Spjd int error; 1635168404Spjd 1636185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1637185029Spjd &nvl)) != 0) 1638185029Spjd return (error); 1639168404Spjd 1640185029Spjd if (zc->zc_cookie) { 1641185029Spjd nvlist_t *origprops; 1642185029Spjd objset_t *os; 1643185029Spjd 1644185029Spjd if (dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1645185029Spjd DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 1646185029Spjd if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { 1647185029Spjd clear_props(zc->zc_name, origprops); 1648185029Spjd nvlist_free(origprops); 1649185029Spjd } 1650185029Spjd dmu_objset_close(os); 1651185029Spjd } 1652185029Spjd 1653168404Spjd } 1654168404Spjd 1655185029Spjd error = zfs_set_prop_nvlist(zc->zc_name, nvl); 1656168404Spjd 1657168404Spjd nvlist_free(nvl); 1658168404Spjd return (error); 1659168404Spjd} 1660168404Spjd 1661185029Spjd/* 1662185029Spjd * inputs: 1663185029Spjd * zc_name name of filesystem 1664185029Spjd * zc_value name of property to inherit 1665185029Spjd * 1666185029Spjd * outputs: none 1667185029Spjd */ 1668168404Spjdstatic int 1669185029Spjdzfs_ioc_inherit_prop(zfs_cmd_t *zc) 1670185029Spjd{ 1671185029Spjd /* the property name has been validated by zfs_secpolicy_inherit() */ 1672185029Spjd return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1673185029Spjd} 1674185029Spjd 1675185029Spjdstatic int 1676169055Spjdzfs_ioc_pool_set_props(zfs_cmd_t *zc) 1677168404Spjd{ 1678185029Spjd nvlist_t *props; 1679168404Spjd spa_t *spa; 1680185029Spjd int error; 1681168404Spjd 1682185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1683185029Spjd &props))) 1684168404Spjd return (error); 1685168404Spjd 1686168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1687185029Spjd nvlist_free(props); 1688168404Spjd return (error); 1689168404Spjd } 1690168404Spjd 1691185029Spjd error = spa_prop_set(spa, props); 1692168404Spjd 1693185029Spjd nvlist_free(props); 1694168404Spjd spa_close(spa, FTAG); 1695168404Spjd 1696168404Spjd return (error); 1697168404Spjd} 1698168404Spjd 1699168404Spjdstatic int 1700169055Spjdzfs_ioc_pool_get_props(zfs_cmd_t *zc) 1701168404Spjd{ 1702168404Spjd spa_t *spa; 1703168404Spjd int error; 1704168404Spjd nvlist_t *nvp = NULL; 1705168404Spjd 1706168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1707168404Spjd return (error); 1708168404Spjd 1709185029Spjd error = spa_prop_get(spa, &nvp); 1710168404Spjd 1711168404Spjd if (error == 0 && zc->zc_nvlist_dst != 0) 1712168404Spjd error = put_nvlist(zc, nvp); 1713168404Spjd else 1714168404Spjd error = EFAULT; 1715168404Spjd 1716168404Spjd spa_close(spa, FTAG); 1717168404Spjd 1718168404Spjd if (nvp) 1719168404Spjd nvlist_free(nvp); 1720168404Spjd return (error); 1721168404Spjd} 1722168404Spjd 1723168404Spjdstatic int 1724185029Spjdzfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) 1725185029Spjd{ 1726185029Spjd#ifdef TODO 1727185029Spjd nvlist_t *nvp; 1728185029Spjd int error; 1729185029Spjd uint32_t uid; 1730185029Spjd uint32_t gid; 1731185029Spjd uint32_t *groups; 1732185029Spjd uint_t group_cnt; 1733185029Spjd cred_t *usercred; 1734185029Spjd 1735185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1736185029Spjd &nvp)) != 0) { 1737185029Spjd return (error); 1738185029Spjd } 1739185029Spjd 1740185029Spjd if ((error = nvlist_lookup_uint32(nvp, 1741185029Spjd ZFS_DELEG_PERM_UID, &uid)) != 0) { 1742185029Spjd nvlist_free(nvp); 1743185029Spjd return (EPERM); 1744185029Spjd } 1745185029Spjd 1746185029Spjd if ((error = nvlist_lookup_uint32(nvp, 1747185029Spjd ZFS_DELEG_PERM_GID, &gid)) != 0) { 1748185029Spjd nvlist_free(nvp); 1749185029Spjd return (EPERM); 1750185029Spjd } 1751185029Spjd 1752185029Spjd if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, 1753185029Spjd &groups, &group_cnt)) != 0) { 1754185029Spjd nvlist_free(nvp); 1755185029Spjd return (EPERM); 1756185029Spjd } 1757185029Spjd usercred = cralloc(); 1758185029Spjd if ((crsetugid(usercred, uid, gid) != 0) || 1759185029Spjd (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { 1760185029Spjd nvlist_free(nvp); 1761185029Spjd crfree(usercred); 1762185029Spjd return (EPERM); 1763185029Spjd } 1764185029Spjd nvlist_free(nvp); 1765185029Spjd error = dsl_deleg_access(zc->zc_name, 1766185029Spjd zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); 1767185029Spjd crfree(usercred); 1768185029Spjd return (error); 1769185029Spjd#else 1770185029Spjd return (EPERM); 1771185029Spjd#endif 1772185029Spjd} 1773185029Spjd 1774185029Spjd/* 1775185029Spjd * inputs: 1776185029Spjd * zc_name name of filesystem 1777185029Spjd * zc_nvlist_src{_size} nvlist of delegated permissions 1778185029Spjd * zc_perm_action allow/unallow flag 1779185029Spjd * 1780185029Spjd * outputs: none 1781185029Spjd */ 1782185029Spjdstatic int 1783185029Spjdzfs_ioc_set_fsacl(zfs_cmd_t *zc) 1784185029Spjd{ 1785185029Spjd int error; 1786185029Spjd nvlist_t *fsaclnv = NULL; 1787185029Spjd 1788185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1789185029Spjd &fsaclnv)) != 0) 1790185029Spjd return (error); 1791185029Spjd 1792185029Spjd /* 1793185029Spjd * Verify nvlist is constructed correctly 1794185029Spjd */ 1795185029Spjd if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 1796185029Spjd nvlist_free(fsaclnv); 1797185029Spjd return (EINVAL); 1798185029Spjd } 1799185029Spjd 1800185029Spjd /* 1801185029Spjd * If we don't have PRIV_SYS_MOUNT, then validate 1802185029Spjd * that user is allowed to hand out each permission in 1803185029Spjd * the nvlist(s) 1804185029Spjd */ 1805185029Spjd 1806185029Spjd error = secpolicy_zfs(CRED()); 1807185029Spjd if (error) { 1808185029Spjd if (zc->zc_perm_action == B_FALSE) { 1809185029Spjd error = dsl_deleg_can_allow(zc->zc_name, 1810185029Spjd fsaclnv, CRED()); 1811185029Spjd } else { 1812185029Spjd error = dsl_deleg_can_unallow(zc->zc_name, 1813185029Spjd fsaclnv, CRED()); 1814185029Spjd } 1815185029Spjd } 1816185029Spjd 1817185029Spjd if (error == 0) 1818185029Spjd error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 1819185029Spjd 1820185029Spjd nvlist_free(fsaclnv); 1821185029Spjd return (error); 1822185029Spjd} 1823185029Spjd 1824185029Spjd/* 1825185029Spjd * inputs: 1826185029Spjd * zc_name name of filesystem 1827185029Spjd * 1828185029Spjd * outputs: 1829185029Spjd * zc_nvlist_src{_size} nvlist of delegated permissions 1830185029Spjd */ 1831185029Spjdstatic int 1832185029Spjdzfs_ioc_get_fsacl(zfs_cmd_t *zc) 1833185029Spjd{ 1834185029Spjd nvlist_t *nvp; 1835185029Spjd int error; 1836185029Spjd 1837185029Spjd if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 1838185029Spjd error = put_nvlist(zc, nvp); 1839185029Spjd nvlist_free(nvp); 1840185029Spjd } 1841185029Spjd 1842185029Spjd return (error); 1843185029Spjd} 1844185029Spjd 1845185029Spjd/* 1846185029Spjd * inputs: 1847185029Spjd * zc_name name of volume 1848185029Spjd * 1849185029Spjd * outputs: none 1850185029Spjd */ 1851185029Spjdstatic int 1852168404Spjdzfs_ioc_create_minor(zfs_cmd_t *zc) 1853168404Spjd{ 1854185029Spjd return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); 1855168404Spjd} 1856168404Spjd 1857185029Spjd/* 1858185029Spjd * inputs: 1859185029Spjd * zc_name name of volume 1860185029Spjd * 1861185029Spjd * outputs: none 1862185029Spjd */ 1863168404Spjdstatic int 1864168404Spjdzfs_ioc_remove_minor(zfs_cmd_t *zc) 1865168404Spjd{ 1866168404Spjd return (zvol_remove_minor(zc->zc_name)); 1867168404Spjd} 1868168404Spjd 1869168404Spjd/* 1870168404Spjd * Search the vfs list for a specified resource. Returns a pointer to it 1871168404Spjd * or NULL if no suitable entry is found. The caller of this routine 1872168404Spjd * is responsible for releasing the returned vfs pointer. 1873168404Spjd */ 1874168404Spjdstatic vfs_t * 1875168404Spjdzfs_get_vfs(const char *resource) 1876168404Spjd{ 1877168404Spjd vfs_t *vfsp; 1878168404Spjd 1879168404Spjd mtx_lock(&mountlist_mtx); 1880168404Spjd TAILQ_FOREACH(vfsp, &mountlist, mnt_list) { 1881185029Spjd if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 1882168404Spjd VFS_HOLD(vfsp); 1883168404Spjd break; 1884168404Spjd } 1885168404Spjd } 1886168404Spjd mtx_unlock(&mountlist_mtx); 1887168404Spjd return (vfsp); 1888168404Spjd} 1889168404Spjd 1890185029Spjd/* ARGSUSED */ 1891168404Spjdstatic void 1892185029Spjdzfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 1893168404Spjd{ 1894185029Spjd zfs_creat_t *zct = arg; 1895168404Spjd 1896185029Spjd zfs_create_fs(os, cr, zct->zct_zplprops, tx); 1897168404Spjd} 1898168404Spjd 1899185029Spjd#define ZFS_PROP_UNDEFINED ((uint64_t)-1) 1900185029Spjd 1901185029Spjd/* 1902185029Spjd * inputs: 1903185029Spjd * createprops list of properties requested by creator 1904185029Spjd * default_zplver zpl version to use if unspecified in createprops 1905185029Spjd * fuids_ok fuids allowed in this version of the spa? 1906185029Spjd * os parent objset pointer (NULL if root fs) 1907185029Spjd * 1908185029Spjd * outputs: 1909185029Spjd * zplprops values for the zplprops we attach to the master node object 1910185029Spjd * is_ci true if requested file system will be purely case-insensitive 1911185029Spjd * 1912185029Spjd * Determine the settings for utf8only, normalization and 1913185029Spjd * casesensitivity. Specific values may have been requested by the 1914185029Spjd * creator and/or we can inherit values from the parent dataset. If 1915185029Spjd * the file system is of too early a vintage, a creator can not 1916185029Spjd * request settings for these properties, even if the requested 1917185029Spjd * setting is the default value. We don't actually want to create dsl 1918185029Spjd * properties for these, so remove them from the source nvlist after 1919185029Spjd * processing. 1920185029Spjd */ 1921168404Spjdstatic int 1922185029Spjdzfs_fill_zplprops_impl(objset_t *os, uint64_t default_zplver, 1923185029Spjd boolean_t fuids_ok, nvlist_t *createprops, nvlist_t *zplprops, 1924185029Spjd boolean_t *is_ci) 1925185029Spjd{ 1926185029Spjd uint64_t zplver = default_zplver; 1927185029Spjd uint64_t sense = ZFS_PROP_UNDEFINED; 1928185029Spjd uint64_t norm = ZFS_PROP_UNDEFINED; 1929185029Spjd uint64_t u8 = ZFS_PROP_UNDEFINED; 1930185029Spjd 1931185029Spjd ASSERT(zplprops != NULL); 1932185029Spjd 1933185029Spjd /* 1934185029Spjd * Pull out creator prop choices, if any. 1935185029Spjd */ 1936185029Spjd if (createprops) { 1937185029Spjd (void) nvlist_lookup_uint64(createprops, 1938185029Spjd zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 1939185029Spjd (void) nvlist_lookup_uint64(createprops, 1940185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 1941185029Spjd (void) nvlist_remove_all(createprops, 1942185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 1943185029Spjd (void) nvlist_lookup_uint64(createprops, 1944185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 1945185029Spjd (void) nvlist_remove_all(createprops, 1946185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 1947185029Spjd (void) nvlist_lookup_uint64(createprops, 1948185029Spjd zfs_prop_to_name(ZFS_PROP_CASE), &sense); 1949185029Spjd (void) nvlist_remove_all(createprops, 1950185029Spjd zfs_prop_to_name(ZFS_PROP_CASE)); 1951185029Spjd } 1952185029Spjd 1953185029Spjd /* 1954185029Spjd * If the zpl version requested is whacky or the file system 1955185029Spjd * or pool is version is too "young" to support normalization 1956185029Spjd * and the creator tried to set a value for one of the props, 1957185029Spjd * error out. 1958185029Spjd */ 1959185029Spjd if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 1960185029Spjd (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 1961185029Spjd (zplver < ZPL_VERSION_NORMALIZATION && 1962185029Spjd (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 1963185029Spjd sense != ZFS_PROP_UNDEFINED))) 1964185029Spjd return (ENOTSUP); 1965185029Spjd 1966185029Spjd /* 1967185029Spjd * Put the version in the zplprops 1968185029Spjd */ 1969185029Spjd VERIFY(nvlist_add_uint64(zplprops, 1970185029Spjd zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 1971185029Spjd 1972185029Spjd if (norm == ZFS_PROP_UNDEFINED) 1973185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 1974185029Spjd VERIFY(nvlist_add_uint64(zplprops, 1975185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 1976185029Spjd 1977185029Spjd /* 1978185029Spjd * If we're normalizing, names must always be valid UTF-8 strings. 1979185029Spjd */ 1980185029Spjd if (norm) 1981185029Spjd u8 = 1; 1982185029Spjd if (u8 == ZFS_PROP_UNDEFINED) 1983185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 1984185029Spjd VERIFY(nvlist_add_uint64(zplprops, 1985185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 1986185029Spjd 1987185029Spjd if (sense == ZFS_PROP_UNDEFINED) 1988185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 1989185029Spjd VERIFY(nvlist_add_uint64(zplprops, 1990185029Spjd zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 1991185029Spjd 1992185029Spjd if (is_ci) 1993185029Spjd *is_ci = (sense == ZFS_CASE_INSENSITIVE); 1994185029Spjd 1995185029Spjd return (0); 1996185029Spjd} 1997185029Spjd 1998185029Spjdstatic int 1999185029Spjdzfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 2000185029Spjd nvlist_t *zplprops, boolean_t *is_ci) 2001185029Spjd{ 2002185029Spjd boolean_t fuids_ok = B_TRUE; 2003185029Spjd uint64_t zplver = ZPL_VERSION; 2004185029Spjd objset_t *os = NULL; 2005185029Spjd char parentname[MAXNAMELEN]; 2006185029Spjd char *cp; 2007185029Spjd int error; 2008185029Spjd 2009185029Spjd (void) strlcpy(parentname, dataset, sizeof (parentname)); 2010185029Spjd cp = strrchr(parentname, '/'); 2011185029Spjd ASSERT(cp != NULL); 2012185029Spjd cp[0] = '\0'; 2013185029Spjd 2014185029Spjd if (zfs_earlier_version(dataset, SPA_VERSION_FUID)) { 2015185029Spjd zplver = ZPL_VERSION_FUID - 1; 2016185029Spjd fuids_ok = B_FALSE; 2017185029Spjd } 2018185029Spjd 2019185029Spjd /* 2020185029Spjd * Open parent object set so we can inherit zplprop values. 2021185029Spjd */ 2022185029Spjd if ((error = dmu_objset_open(parentname, DMU_OST_ANY, 2023185029Spjd DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) 2024185029Spjd return (error); 2025185029Spjd 2026185029Spjd error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, createprops, 2027185029Spjd zplprops, is_ci); 2028185029Spjd dmu_objset_close(os); 2029185029Spjd return (error); 2030185029Spjd} 2031185029Spjd 2032185029Spjdstatic int 2033185029Spjdzfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 2034185029Spjd nvlist_t *zplprops, boolean_t *is_ci) 2035185029Spjd{ 2036185029Spjd boolean_t fuids_ok = B_TRUE; 2037185029Spjd uint64_t zplver = ZPL_VERSION; 2038185029Spjd int error; 2039185029Spjd 2040185029Spjd if (spa_vers < SPA_VERSION_FUID) { 2041185029Spjd zplver = ZPL_VERSION_FUID - 1; 2042185029Spjd fuids_ok = B_FALSE; 2043185029Spjd } 2044185029Spjd 2045185029Spjd error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, createprops, 2046185029Spjd zplprops, is_ci); 2047185029Spjd return (error); 2048185029Spjd} 2049185029Spjd 2050185029Spjd/* 2051185029Spjd * inputs: 2052185029Spjd * zc_objset_type type of objset to create (fs vs zvol) 2053185029Spjd * zc_name name of new objset 2054185029Spjd * zc_value name of snapshot to clone from (may be empty) 2055185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 2056185029Spjd * 2057185029Spjd * outputs: none 2058185029Spjd */ 2059185029Spjdstatic int 2060168404Spjdzfs_ioc_create(zfs_cmd_t *zc) 2061168404Spjd{ 2062168404Spjd objset_t *clone; 2063168404Spjd int error = 0; 2064185029Spjd zfs_creat_t zct; 2065185029Spjd nvlist_t *nvprops = NULL; 2066185029Spjd void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2067168404Spjd dmu_objset_type_t type = zc->zc_objset_type; 2068168404Spjd 2069168404Spjd switch (type) { 2070168404Spjd 2071168404Spjd case DMU_OST_ZFS: 2072168404Spjd cbfunc = zfs_create_cb; 2073168404Spjd break; 2074168404Spjd 2075168404Spjd case DMU_OST_ZVOL: 2076168404Spjd cbfunc = zvol_create_cb; 2077168404Spjd break; 2078168404Spjd 2079168404Spjd default: 2080168404Spjd cbfunc = NULL; 2081185029Spjd break; 2082168404Spjd } 2083185029Spjd if (strchr(zc->zc_name, '@') || 2084185029Spjd strchr(zc->zc_name, '%')) 2085168404Spjd return (EINVAL); 2086168404Spjd 2087168404Spjd if (zc->zc_nvlist_src != 0 && 2088185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2089185029Spjd &nvprops)) != 0) 2090168404Spjd return (error); 2091168404Spjd 2092185029Spjd zct.zct_zplprops = NULL; 2093185029Spjd zct.zct_props = nvprops; 2094168404Spjd 2095168404Spjd if (zc->zc_value[0] != '\0') { 2096168404Spjd /* 2097168404Spjd * We're creating a clone of an existing snapshot. 2098168404Spjd */ 2099168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2100168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 2101185029Spjd nvlist_free(nvprops); 2102168404Spjd return (EINVAL); 2103168404Spjd } 2104168404Spjd 2105168404Spjd error = dmu_objset_open(zc->zc_value, type, 2106185029Spjd DS_MODE_USER | DS_MODE_READONLY, &clone); 2107168404Spjd if (error) { 2108185029Spjd nvlist_free(nvprops); 2109168404Spjd return (error); 2110168404Spjd } 2111185029Spjd 2112185029Spjd error = dmu_objset_create(zc->zc_name, type, clone, 0, 2113185029Spjd NULL, NULL); 2114185029Spjd if (error) { 2115185029Spjd dmu_objset_close(clone); 2116185029Spjd nvlist_free(nvprops); 2117185029Spjd return (error); 2118185029Spjd } 2119168404Spjd dmu_objset_close(clone); 2120168404Spjd } else { 2121185029Spjd boolean_t is_insensitive = B_FALSE; 2122185029Spjd 2123168404Spjd if (cbfunc == NULL) { 2124185029Spjd nvlist_free(nvprops); 2125168404Spjd return (EINVAL); 2126168404Spjd } 2127168404Spjd 2128168404Spjd if (type == DMU_OST_ZVOL) { 2129168404Spjd uint64_t volsize, volblocksize; 2130168404Spjd 2131185029Spjd if (nvprops == NULL || 2132185029Spjd nvlist_lookup_uint64(nvprops, 2133168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 2134168404Spjd &volsize) != 0) { 2135185029Spjd nvlist_free(nvprops); 2136168404Spjd return (EINVAL); 2137168404Spjd } 2138168404Spjd 2139185029Spjd if ((error = nvlist_lookup_uint64(nvprops, 2140168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2141168404Spjd &volblocksize)) != 0 && error != ENOENT) { 2142185029Spjd nvlist_free(nvprops); 2143168404Spjd return (EINVAL); 2144168404Spjd } 2145168404Spjd 2146168404Spjd if (error != 0) 2147168404Spjd volblocksize = zfs_prop_default_numeric( 2148168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2149168404Spjd 2150168404Spjd if ((error = zvol_check_volblocksize( 2151168404Spjd volblocksize)) != 0 || 2152168404Spjd (error = zvol_check_volsize(volsize, 2153168404Spjd volblocksize)) != 0) { 2154185029Spjd nvlist_free(nvprops); 2155168404Spjd return (error); 2156168404Spjd } 2157185029Spjd } else if (type == DMU_OST_ZFS) { 2158185029Spjd int error; 2159185029Spjd 2160185029Spjd /* 2161185029Spjd * We have to have normalization and 2162185029Spjd * case-folding flags correct when we do the 2163185029Spjd * file system creation, so go figure them out 2164185029Spjd * now. 2165185029Spjd */ 2166185029Spjd VERIFY(nvlist_alloc(&zct.zct_zplprops, 2167185029Spjd NV_UNIQUE_NAME, KM_SLEEP) == 0); 2168185029Spjd error = zfs_fill_zplprops(zc->zc_name, nvprops, 2169185029Spjd zct.zct_zplprops, &is_insensitive); 2170185029Spjd if (error != 0) { 2171185029Spjd nvlist_free(nvprops); 2172185029Spjd nvlist_free(zct.zct_zplprops); 2173185029Spjd return (error); 2174185029Spjd } 2175168404Spjd } 2176185029Spjd error = dmu_objset_create(zc->zc_name, type, NULL, 2177185029Spjd is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 2178185029Spjd nvlist_free(zct.zct_zplprops); 2179168404Spjd } 2180168404Spjd 2181168404Spjd /* 2182168404Spjd * It would be nice to do this atomically. 2183168404Spjd */ 2184168404Spjd if (error == 0) { 2185185029Spjd if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) 2186168404Spjd (void) dmu_objset_destroy(zc->zc_name); 2187168404Spjd } 2188185029Spjd nvlist_free(nvprops); 2189168404Spjd return (error); 2190168404Spjd} 2191168404Spjd 2192185029Spjdstruct snap_prop_arg { 2193185029Spjd nvlist_t *nvprops; 2194185029Spjd const char *snapname; 2195185029Spjd}; 2196185029Spjd 2197168404Spjdstatic int 2198185029Spjdset_snap_props(char *name, void *arg) 2199185029Spjd{ 2200185029Spjd struct snap_prop_arg *snpa = arg; 2201185029Spjd int len = strlen(name) + strlen(snpa->snapname) + 2; 2202185029Spjd char *buf = kmem_alloc(len, KM_SLEEP); 2203185029Spjd int err; 2204185029Spjd 2205185029Spjd (void) snprintf(buf, len, "%s@%s", name, snpa->snapname); 2206185029Spjd err = zfs_set_prop_nvlist(buf, snpa->nvprops); 2207185029Spjd if (err) 2208185029Spjd (void) dmu_objset_destroy(buf); 2209185029Spjd kmem_free(buf, len); 2210185029Spjd return (err); 2211185029Spjd} 2212185029Spjd 2213185029Spjd/* 2214185029Spjd * inputs: 2215185029Spjd * zc_name name of filesystem 2216185029Spjd * zc_value short name of snapshot 2217185029Spjd * zc_cookie recursive flag 2218185029Spjd * 2219185029Spjd * outputs: none 2220185029Spjd */ 2221185029Spjdstatic int 2222168404Spjdzfs_ioc_snapshot(zfs_cmd_t *zc) 2223168404Spjd{ 2224185029Spjd nvlist_t *nvprops = NULL; 2225185029Spjd int error; 2226185029Spjd boolean_t recursive = zc->zc_cookie; 2227185029Spjd 2228168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 2229168404Spjd return (EINVAL); 2230185029Spjd 2231185029Spjd if (zc->zc_nvlist_src != 0 && 2232185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2233185029Spjd &nvprops)) != 0) 2234185029Spjd return (error); 2235185029Spjd 2236185029Spjd error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, recursive); 2237185029Spjd 2238185029Spjd /* 2239185029Spjd * It would be nice to do this atomically. 2240185029Spjd */ 2241185029Spjd if (error == 0) { 2242185029Spjd struct snap_prop_arg snpa; 2243185029Spjd snpa.nvprops = nvprops; 2244185029Spjd snpa.snapname = zc->zc_value; 2245185029Spjd if (recursive) { 2246185029Spjd error = dmu_objset_find(zc->zc_name, 2247185029Spjd set_snap_props, &snpa, DS_FIND_CHILDREN); 2248185029Spjd if (error) { 2249185029Spjd (void) dmu_snapshots_destroy(zc->zc_name, 2250185029Spjd zc->zc_value); 2251185029Spjd } 2252185029Spjd } else { 2253185029Spjd error = set_snap_props(zc->zc_name, &snpa); 2254185029Spjd } 2255185029Spjd } 2256185029Spjd nvlist_free(nvprops); 2257185029Spjd return (error); 2258168404Spjd} 2259168404Spjd 2260168676Spjdint 2261168404Spjdzfs_unmount_snap(char *name, void *arg) 2262168404Spjd{ 2263168404Spjd vfs_t *vfsp = NULL; 2264168404Spjd 2265185029Spjd if (arg) { 2266185029Spjd char *snapname = arg; 2267185029Spjd int len = strlen(name) + strlen(snapname) + 2; 2268185029Spjd char *buf = kmem_alloc(len, KM_SLEEP); 2269168404Spjd 2270185029Spjd (void) strcpy(buf, name); 2271185029Spjd (void) strcat(buf, "@"); 2272185029Spjd (void) strcat(buf, snapname); 2273185029Spjd vfsp = zfs_get_vfs(buf); 2274185029Spjd kmem_free(buf, len); 2275168404Spjd } else if (strchr(name, '@')) { 2276168404Spjd vfsp = zfs_get_vfs(name); 2277168404Spjd } 2278168404Spjd 2279168404Spjd if (vfsp) { 2280168404Spjd /* 2281168404Spjd * Always force the unmount for snapshots. 2282168404Spjd */ 2283168404Spjd int flag = MS_FORCE; 2284168404Spjd int err; 2285168404Spjd 2286168404Spjd if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 2287168404Spjd VFS_RELE(vfsp); 2288168404Spjd return (err); 2289168404Spjd } 2290168404Spjd VFS_RELE(vfsp); 2291168404Spjd mtx_lock(&Giant); /* dounmount() */ 2292168404Spjd dounmount(vfsp, flag, curthread); 2293168404Spjd mtx_unlock(&Giant); /* dounmount() */ 2294168404Spjd } 2295168404Spjd return (0); 2296168404Spjd} 2297168404Spjd 2298185029Spjd/* 2299185029Spjd * inputs: 2300185029Spjd * zc_name name of filesystem 2301185029Spjd * zc_value short name of snapshot 2302185029Spjd * 2303185029Spjd * outputs: none 2304185029Spjd */ 2305168404Spjdstatic int 2306168404Spjdzfs_ioc_destroy_snaps(zfs_cmd_t *zc) 2307168404Spjd{ 2308168404Spjd int err; 2309168404Spjd 2310168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 2311168404Spjd return (EINVAL); 2312168404Spjd err = dmu_objset_find(zc->zc_name, 2313168404Spjd zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 2314168404Spjd if (err) 2315168404Spjd return (err); 2316168404Spjd return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 2317168404Spjd} 2318168404Spjd 2319185029Spjd/* 2320185029Spjd * inputs: 2321185029Spjd * zc_name name of dataset to destroy 2322185029Spjd * zc_objset_type type of objset 2323185029Spjd * 2324185029Spjd * outputs: none 2325185029Spjd */ 2326168404Spjdstatic int 2327168404Spjdzfs_ioc_destroy(zfs_cmd_t *zc) 2328168404Spjd{ 2329168404Spjd if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 2330168404Spjd int err = zfs_unmount_snap(zc->zc_name, NULL); 2331168404Spjd if (err) 2332168404Spjd return (err); 2333168404Spjd } 2334168404Spjd 2335168404Spjd return (dmu_objset_destroy(zc->zc_name)); 2336168404Spjd} 2337168404Spjd 2338185029Spjd/* 2339185029Spjd * inputs: 2340185029Spjd * zc_name name of dataset to rollback (to most recent snapshot) 2341185029Spjd * 2342185029Spjd * outputs: none 2343185029Spjd */ 2344168404Spjdstatic int 2345168404Spjdzfs_ioc_rollback(zfs_cmd_t *zc) 2346168404Spjd{ 2347185029Spjd objset_t *os; 2348185029Spjd int error; 2349185029Spjd zfsvfs_t *zfsvfs = NULL; 2350185029Spjd 2351185029Spjd /* 2352185029Spjd * Get the zfsvfs for the receiving objset. There 2353185029Spjd * won't be one if we're operating on a zvol, if the 2354185029Spjd * objset doesn't exist yet, or is not mounted. 2355185029Spjd */ 2356185029Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, DS_MODE_USER, &os); 2357185029Spjd if (error) 2358185029Spjd return (error); 2359185029Spjd 2360185029Spjd if (dmu_objset_type(os) == DMU_OST_ZFS) { 2361185029Spjd mutex_enter(&os->os->os_user_ptr_lock); 2362185029Spjd zfsvfs = dmu_objset_get_user(os); 2363185029Spjd if (zfsvfs != NULL) 2364185029Spjd VFS_HOLD(zfsvfs->z_vfs); 2365185029Spjd mutex_exit(&os->os->os_user_ptr_lock); 2366185029Spjd } 2367185029Spjd 2368185029Spjd if (zfsvfs != NULL) { 2369185029Spjd char osname[MAXNAMELEN]; 2370185029Spjd int mode; 2371185029Spjd 2372185029Spjd error = zfs_suspend_fs(zfsvfs, osname, &mode); 2373185029Spjd if (error == 0) { 2374185029Spjd int resume_err; 2375185029Spjd 2376185029Spjd ASSERT(strcmp(osname, zc->zc_name) == 0); 2377185029Spjd error = dmu_objset_rollback(os); 2378185029Spjd resume_err = zfs_resume_fs(zfsvfs, osname, mode); 2379185029Spjd error = error ? error : resume_err; 2380185029Spjd } else { 2381185029Spjd dmu_objset_close(os); 2382185029Spjd } 2383185029Spjd VFS_RELE(zfsvfs->z_vfs); 2384185029Spjd } else { 2385185029Spjd error = dmu_objset_rollback(os); 2386185029Spjd } 2387185029Spjd /* Note, the dmu_objset_rollback() releases the objset for us. */ 2388185029Spjd 2389185029Spjd return (error); 2390168404Spjd} 2391168404Spjd 2392185029Spjd/* 2393185029Spjd * inputs: 2394185029Spjd * zc_name old name of dataset 2395185029Spjd * zc_value new name of dataset 2396185029Spjd * zc_cookie recursive flag (only valid for snapshots) 2397185029Spjd * 2398185029Spjd * outputs: none 2399185029Spjd */ 2400168404Spjdstatic int 2401168404Spjdzfs_ioc_rename(zfs_cmd_t *zc) 2402168404Spjd{ 2403185029Spjd boolean_t recursive = zc->zc_cookie & 1; 2404168676Spjd 2405168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2406185029Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2407185029Spjd strchr(zc->zc_value, '%')) 2408168404Spjd return (EINVAL); 2409168404Spjd 2410168676Spjd /* 2411168676Spjd * Unmount snapshot unless we're doing a recursive rename, 2412168676Spjd * in which case the dataset code figures out which snapshots 2413168676Spjd * to unmount. 2414168676Spjd */ 2415168676Spjd if (!recursive && strchr(zc->zc_name, '@') != NULL && 2416168404Spjd zc->zc_objset_type == DMU_OST_ZFS) { 2417168404Spjd int err = zfs_unmount_snap(zc->zc_name, NULL); 2418168404Spjd if (err) 2419168404Spjd return (err); 2420168404Spjd } 2421168676Spjd return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 2422168404Spjd} 2423168404Spjd 2424185029Spjdstatic void 2425185029Spjdclear_props(char *dataset, nvlist_t *props) 2426185029Spjd{ 2427185029Spjd zfs_cmd_t *zc; 2428185029Spjd nvpair_t *prop; 2429185029Spjd 2430185029Spjd if (props == NULL) 2431185029Spjd return; 2432185029Spjd zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 2433185029Spjd (void) strcpy(zc->zc_name, dataset); 2434185029Spjd for (prop = nvlist_next_nvpair(props, NULL); prop; 2435185029Spjd prop = nvlist_next_nvpair(props, prop)) { 2436185029Spjd (void) strcpy(zc->zc_value, nvpair_name(prop)); 2437185029Spjd if (zfs_secpolicy_inherit(zc, CRED()) == 0) 2438185029Spjd (void) zfs_ioc_inherit_prop(zc); 2439185029Spjd } 2440185029Spjd kmem_free(zc, sizeof (zfs_cmd_t)); 2441185029Spjd} 2442185029Spjd 2443185029Spjd/* 2444185029Spjd * inputs: 2445185029Spjd * zc_name name of containing filesystem 2446185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 2447185029Spjd * zc_value name of snapshot to create 2448185029Spjd * zc_string name of clone origin (if DRR_FLAG_CLONE) 2449185029Spjd * zc_cookie file descriptor to recv from 2450185029Spjd * zc_begin_record the BEGIN record of the stream (not byteswapped) 2451185029Spjd * zc_guid force flag 2452185029Spjd * 2453185029Spjd * outputs: 2454185029Spjd * zc_cookie number of bytes read 2455185029Spjd */ 2456168404Spjdstatic int 2457185029Spjdzfs_ioc_recv(zfs_cmd_t *zc) 2458168404Spjd{ 2459185029Spjd file_t *fp; 2460185029Spjd objset_t *os; 2461185029Spjd dmu_recv_cookie_t drc; 2462185029Spjd zfsvfs_t *zfsvfs = NULL; 2463185029Spjd boolean_t force = (boolean_t)zc->zc_guid; 2464185029Spjd int error, fd; 2465185029Spjd offset_t off; 2466185029Spjd nvlist_t *props = NULL; 2467185029Spjd nvlist_t *origprops = NULL; 2468185029Spjd objset_t *origin = NULL; 2469185029Spjd char *tosnap; 2470185029Spjd char tofs[ZFS_MAXNAMELEN]; 2471168404Spjd 2472168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 2473185029Spjd strchr(zc->zc_value, '@') == NULL || 2474185029Spjd strchr(zc->zc_value, '%')) 2475168404Spjd return (EINVAL); 2476168404Spjd 2477185029Spjd (void) strcpy(tofs, zc->zc_value); 2478185029Spjd tosnap = strchr(tofs, '@'); 2479185029Spjd *tosnap = '\0'; 2480185029Spjd tosnap++; 2481185029Spjd 2482185029Spjd if (zc->zc_nvlist_src != 0 && 2483185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2484185029Spjd &props)) != 0) 2485168404Spjd return (error); 2486168404Spjd 2487185029Spjd fd = zc->zc_cookie; 2488185029Spjd fp = getf(fd, 0); 2489185029Spjd if (fp == NULL) { 2490185029Spjd nvlist_free(props); 2491185029Spjd return (EBADF); 2492185029Spjd } 2493168404Spjd 2494185029Spjd if (dmu_objset_open(tofs, DMU_OST_ANY, 2495185029Spjd DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { 2496185029Spjd /* 2497185029Spjd * Try to get the zfsvfs for the receiving objset. 2498185029Spjd * There won't be one if we're operating on a zvol, 2499185029Spjd * if the objset doesn't exist yet, or is not mounted. 2500185029Spjd */ 2501185029Spjd mutex_enter(&os->os->os_user_ptr_lock); 2502185029Spjd if (zfsvfs = dmu_objset_get_user(os)) { 2503185029Spjd if (!mutex_tryenter(&zfsvfs->z_online_recv_lock)) { 2504185029Spjd mutex_exit(&os->os->os_user_ptr_lock); 2505185029Spjd dmu_objset_close(os); 2506185029Spjd zfsvfs = NULL; 2507185029Spjd error = EBUSY; 2508185029Spjd goto out; 2509185029Spjd } 2510185029Spjd VFS_HOLD(zfsvfs->z_vfs); 2511185029Spjd } 2512185029Spjd mutex_exit(&os->os->os_user_ptr_lock); 2513168404Spjd 2514185029Spjd /* 2515185029Spjd * If new properties are supplied, they are to completely 2516185029Spjd * replace the existing ones, so stash away the existing ones. 2517185029Spjd */ 2518185029Spjd if (props) 2519185029Spjd (void) dsl_prop_get_all(os, &origprops, TRUE); 2520185029Spjd 2521185029Spjd dmu_objset_close(os); 2522185029Spjd } 2523185029Spjd 2524185029Spjd if (zc->zc_string[0]) { 2525185029Spjd error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, 2526185029Spjd DS_MODE_USER | DS_MODE_READONLY, &origin); 2527185029Spjd if (error) 2528185029Spjd goto out; 2529185029Spjd } 2530185029Spjd 2531185029Spjd error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, 2532185029Spjd force, origin, zfsvfs != NULL, &drc); 2533185029Spjd if (origin) 2534185029Spjd dmu_objset_close(origin); 2535185029Spjd if (error) 2536185029Spjd goto out; 2537185029Spjd 2538185029Spjd /* 2539185029Spjd * Reset properties. We do this before we receive the stream 2540185029Spjd * so that the properties are applied to the new data. 2541185029Spjd */ 2542185029Spjd if (props) { 2543185029Spjd clear_props(tofs, origprops); 2544185029Spjd /* 2545185029Spjd * XXX - Note, this is all-or-nothing; should be best-effort. 2546185029Spjd */ 2547185029Spjd (void) zfs_set_prop_nvlist(tofs, props); 2548185029Spjd } 2549185029Spjd 2550185029Spjd off = fp->f_offset; 2551185029Spjd error = dmu_recv_stream(&drc, fp, &off); 2552185029Spjd 2553185029Spjd if (error == 0 && zfsvfs) { 2554185029Spjd char osname[MAXNAMELEN]; 2555185029Spjd int mode; 2556185029Spjd 2557185029Spjd /* online recv */ 2558185029Spjd error = zfs_suspend_fs(zfsvfs, osname, &mode); 2559185029Spjd if (error == 0) { 2560185029Spjd int resume_err; 2561185029Spjd 2562185029Spjd error = dmu_recv_end(&drc); 2563185029Spjd resume_err = zfs_resume_fs(zfsvfs, osname, mode); 2564185029Spjd error = error ? error : resume_err; 2565185029Spjd } else { 2566185029Spjd dmu_recv_abort_cleanup(&drc); 2567185029Spjd } 2568185029Spjd } else if (error == 0) { 2569185029Spjd error = dmu_recv_end(&drc); 2570185029Spjd } 2571185029Spjd 2572185029Spjd zc->zc_cookie = off - fp->f_offset; 2573185029Spjd if (off >= 0 && off <= MAXOFFSET_T) 2574185029Spjd fp->f_offset = off; 2575185029Spjd 2576185029Spjd /* 2577185029Spjd * On error, restore the original props. 2578185029Spjd */ 2579185029Spjd if (error && props) { 2580185029Spjd clear_props(tofs, props); 2581185029Spjd (void) zfs_set_prop_nvlist(tofs, origprops); 2582185029Spjd } 2583185029Spjdout: 2584185029Spjd if (zfsvfs) { 2585185029Spjd mutex_exit(&zfsvfs->z_online_recv_lock); 2586185029Spjd VFS_RELE(zfsvfs->z_vfs); 2587185029Spjd } 2588185029Spjd nvlist_free(props); 2589185029Spjd nvlist_free(origprops); 2590185029Spjd releasef(fp); 2591168404Spjd return (error); 2592168404Spjd} 2593168404Spjd 2594185029Spjd/* 2595185029Spjd * inputs: 2596185029Spjd * zc_name name of snapshot to send 2597185029Spjd * zc_value short name of incremental fromsnap (may be empty) 2598185029Spjd * zc_cookie file descriptor to send stream to 2599185029Spjd * zc_obj fromorigin flag (mutually exclusive with zc_value) 2600185029Spjd * 2601185029Spjd * outputs: none 2602185029Spjd */ 2603168404Spjdstatic int 2604185029Spjdzfs_ioc_send(zfs_cmd_t *zc) 2605168404Spjd{ 2606168404Spjd objset_t *fromsnap = NULL; 2607168404Spjd objset_t *tosnap; 2608185029Spjd file_t *fp; 2609185029Spjd int error; 2610185029Spjd offset_t off; 2611168404Spjd 2612168404Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 2613185029Spjd DS_MODE_USER | DS_MODE_READONLY, &tosnap); 2614168404Spjd if (error) 2615168404Spjd return (error); 2616168404Spjd 2617168404Spjd if (zc->zc_value[0] != '\0') { 2618168404Spjd char buf[MAXPATHLEN]; 2619168404Spjd char *cp; 2620168404Spjd 2621168404Spjd (void) strncpy(buf, zc->zc_name, sizeof (buf)); 2622168404Spjd cp = strchr(buf, '@'); 2623168404Spjd if (cp) 2624168404Spjd *(cp+1) = 0; 2625168404Spjd (void) strlcat(buf, zc->zc_value, sizeof (buf)); 2626168404Spjd error = dmu_objset_open(buf, DMU_OST_ANY, 2627185029Spjd DS_MODE_USER | DS_MODE_READONLY, &fromsnap); 2628168404Spjd if (error) { 2629168404Spjd dmu_objset_close(tosnap); 2630168404Spjd return (error); 2631168404Spjd } 2632168404Spjd } 2633168404Spjd 2634185029Spjd fp = getf(zc->zc_cookie, 1); 2635185029Spjd if (fp == NULL) { 2636168404Spjd dmu_objset_close(tosnap); 2637168404Spjd if (fromsnap) 2638168404Spjd dmu_objset_close(fromsnap); 2639185029Spjd return (EBADF); 2640168404Spjd } 2641168404Spjd 2642185029Spjd off = fp->f_offset; 2643185029Spjd error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp, &off); 2644168404Spjd 2645185029Spjd if (off >= 0 && off <= MAXOFFSET_T) 2646185029Spjd fp->f_offset = off; 2647185029Spjd releasef(fp); 2648168404Spjd if (fromsnap) 2649168404Spjd dmu_objset_close(fromsnap); 2650168404Spjd dmu_objset_close(tosnap); 2651168404Spjd return (error); 2652168404Spjd} 2653168404Spjd 2654168404Spjdstatic int 2655168404Spjdzfs_ioc_inject_fault(zfs_cmd_t *zc) 2656168404Spjd{ 2657168404Spjd int id, error; 2658168404Spjd 2659168404Spjd error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 2660168404Spjd &zc->zc_inject_record); 2661168404Spjd 2662168404Spjd if (error == 0) 2663168404Spjd zc->zc_guid = (uint64_t)id; 2664168404Spjd 2665168404Spjd return (error); 2666168404Spjd} 2667168404Spjd 2668168404Spjdstatic int 2669168404Spjdzfs_ioc_clear_fault(zfs_cmd_t *zc) 2670168404Spjd{ 2671168404Spjd return (zio_clear_fault((int)zc->zc_guid)); 2672168404Spjd} 2673168404Spjd 2674168404Spjdstatic int 2675168404Spjdzfs_ioc_inject_list_next(zfs_cmd_t *zc) 2676168404Spjd{ 2677168404Spjd int id = (int)zc->zc_guid; 2678168404Spjd int error; 2679168404Spjd 2680168404Spjd error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 2681168404Spjd &zc->zc_inject_record); 2682168404Spjd 2683168404Spjd zc->zc_guid = id; 2684168404Spjd 2685168404Spjd return (error); 2686168404Spjd} 2687168404Spjd 2688168404Spjdstatic int 2689168404Spjdzfs_ioc_error_log(zfs_cmd_t *zc) 2690168404Spjd{ 2691168404Spjd spa_t *spa; 2692168404Spjd int error; 2693168404Spjd size_t count = (size_t)zc->zc_nvlist_dst_size; 2694168404Spjd 2695168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2696168404Spjd return (error); 2697168404Spjd 2698168404Spjd error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 2699168404Spjd &count); 2700168404Spjd if (error == 0) 2701168404Spjd zc->zc_nvlist_dst_size = count; 2702168404Spjd else 2703168404Spjd zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 2704168404Spjd 2705168404Spjd spa_close(spa, FTAG); 2706168404Spjd 2707168404Spjd return (error); 2708168404Spjd} 2709168404Spjd 2710168404Spjdstatic int 2711168404Spjdzfs_ioc_clear(zfs_cmd_t *zc) 2712168404Spjd{ 2713168404Spjd spa_t *spa; 2714168404Spjd vdev_t *vd; 2715168404Spjd int error; 2716168404Spjd 2717185029Spjd /* 2718185029Spjd * On zpool clear we also fix up missing slogs 2719185029Spjd */ 2720185029Spjd mutex_enter(&spa_namespace_lock); 2721185029Spjd spa = spa_lookup(zc->zc_name); 2722185029Spjd if (spa == NULL) { 2723185029Spjd mutex_exit(&spa_namespace_lock); 2724185029Spjd return (EIO); 2725185029Spjd } 2726185029Spjd if (spa->spa_log_state == SPA_LOG_MISSING) { 2727185029Spjd /* we need to let spa_open/spa_load clear the chains */ 2728185029Spjd spa->spa_log_state = SPA_LOG_CLEAR; 2729185029Spjd } 2730185029Spjd mutex_exit(&spa_namespace_lock); 2731185029Spjd 2732168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2733168404Spjd return (error); 2734168404Spjd 2735185029Spjd spa_vdev_state_enter(spa); 2736168404Spjd 2737168404Spjd if (zc->zc_guid == 0) { 2738168404Spjd vd = NULL; 2739185029Spjd } else { 2740185029Spjd vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 2741185029Spjd if (vd == NULL) { 2742185029Spjd (void) spa_vdev_state_exit(spa, NULL, ENODEV); 2743185029Spjd spa_close(spa, FTAG); 2744185029Spjd return (ENODEV); 2745185029Spjd } 2746168404Spjd } 2747168404Spjd 2748168404Spjd vdev_clear(spa, vd); 2749168404Spjd 2750185029Spjd (void) spa_vdev_state_exit(spa, NULL, 0); 2751168404Spjd 2752185029Spjd /* 2753185029Spjd * Resume any suspended I/Os. 2754185029Spjd */ 2755185029Spjd zio_resume(spa); 2756185029Spjd 2757168404Spjd spa_close(spa, FTAG); 2758168404Spjd 2759168404Spjd return (0); 2760168404Spjd} 2761168404Spjd 2762185029Spjd/* 2763185029Spjd * inputs: 2764185029Spjd * zc_name name of filesystem 2765185029Spjd * zc_value name of origin snapshot 2766185029Spjd * 2767185029Spjd * outputs: none 2768185029Spjd */ 2769168404Spjdstatic int 2770168404Spjdzfs_ioc_promote(zfs_cmd_t *zc) 2771168404Spjd{ 2772168404Spjd char *cp; 2773168404Spjd 2774168404Spjd /* 2775168404Spjd * We don't need to unmount *all* the origin fs's snapshots, but 2776168404Spjd * it's easier. 2777168404Spjd */ 2778168404Spjd cp = strchr(zc->zc_value, '@'); 2779168404Spjd if (cp) 2780168404Spjd *cp = '\0'; 2781168404Spjd (void) dmu_objset_find(zc->zc_value, 2782168404Spjd zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 2783168404Spjd return (dsl_dataset_promote(zc->zc_name)); 2784168404Spjd} 2785168404Spjd 2786185029Spjd#ifdef TODO 2787185029Spjd/* 2788185029Spjd * We don't want to have a hard dependency 2789185029Spjd * against some special symbols in sharefs 2790185029Spjd * nfs, and smbsrv. Determine them if needed when 2791185029Spjd * the first file system is shared. 2792185029Spjd * Neither sharefs, nfs or smbsrv are unloadable modules. 2793185029Spjd */ 2794185029Spjdint (*znfsexport_fs)(void *arg); 2795185029Spjdint (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 2796185029Spjdint (*zsmbexport_fs)(void *arg, boolean_t add_share); 2797185029Spjd 2798185029Spjdint zfs_nfsshare_inited; 2799185029Spjdint zfs_smbshare_inited; 2800185029Spjd 2801185029Spjdddi_modhandle_t nfs_mod; 2802185029Spjdddi_modhandle_t sharefs_mod; 2803185029Spjdddi_modhandle_t smbsrv_mod; 2804185029Spjd#endif 2805185029Spjdkmutex_t zfs_share_lock; 2806185029Spjd 2807185029Spjd#ifdef TODO 2808168404Spjdstatic int 2809185029Spjdzfs_init_sharefs() 2810185029Spjd{ 2811185029Spjd int error; 2812185029Spjd 2813185029Spjd ASSERT(MUTEX_HELD(&zfs_share_lock)); 2814185029Spjd /* Both NFS and SMB shares also require sharetab support. */ 2815185029Spjd if (sharefs_mod == NULL && ((sharefs_mod = 2816185029Spjd ddi_modopen("fs/sharefs", 2817185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 2818185029Spjd return (ENOSYS); 2819185029Spjd } 2820185029Spjd if (zshare_fs == NULL && ((zshare_fs = 2821185029Spjd (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 2822185029Spjd ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 2823185029Spjd return (ENOSYS); 2824185029Spjd } 2825185029Spjd return (0); 2826185029Spjd} 2827185029Spjd#endif 2828185029Spjd 2829185029Spjdstatic int 2830185029Spjdzfs_ioc_share(zfs_cmd_t *zc) 2831185029Spjd{ 2832185029Spjd#ifdef TODO 2833185029Spjd int error; 2834185029Spjd int opcode; 2835185029Spjd 2836185029Spjd switch (zc->zc_share.z_sharetype) { 2837185029Spjd case ZFS_SHARE_NFS: 2838185029Spjd case ZFS_UNSHARE_NFS: 2839185029Spjd if (zfs_nfsshare_inited == 0) { 2840185029Spjd mutex_enter(&zfs_share_lock); 2841185029Spjd if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 2842185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 2843185029Spjd mutex_exit(&zfs_share_lock); 2844185029Spjd return (ENOSYS); 2845185029Spjd } 2846185029Spjd if (znfsexport_fs == NULL && 2847185029Spjd ((znfsexport_fs = (int (*)(void *)) 2848185029Spjd ddi_modsym(nfs_mod, 2849185029Spjd "nfs_export", &error)) == NULL)) { 2850185029Spjd mutex_exit(&zfs_share_lock); 2851185029Spjd return (ENOSYS); 2852185029Spjd } 2853185029Spjd error = zfs_init_sharefs(); 2854185029Spjd if (error) { 2855185029Spjd mutex_exit(&zfs_share_lock); 2856185029Spjd return (ENOSYS); 2857185029Spjd } 2858185029Spjd zfs_nfsshare_inited = 1; 2859185029Spjd mutex_exit(&zfs_share_lock); 2860185029Spjd } 2861185029Spjd break; 2862185029Spjd case ZFS_SHARE_SMB: 2863185029Spjd case ZFS_UNSHARE_SMB: 2864185029Spjd if (zfs_smbshare_inited == 0) { 2865185029Spjd mutex_enter(&zfs_share_lock); 2866185029Spjd if (smbsrv_mod == NULL && ((smbsrv_mod = 2867185029Spjd ddi_modopen("drv/smbsrv", 2868185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 2869185029Spjd mutex_exit(&zfs_share_lock); 2870185029Spjd return (ENOSYS); 2871185029Spjd } 2872185029Spjd if (zsmbexport_fs == NULL && ((zsmbexport_fs = 2873185029Spjd (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 2874185029Spjd "smb_server_share", &error)) == NULL)) { 2875185029Spjd mutex_exit(&zfs_share_lock); 2876185029Spjd return (ENOSYS); 2877185029Spjd } 2878185029Spjd error = zfs_init_sharefs(); 2879185029Spjd if (error) { 2880185029Spjd mutex_exit(&zfs_share_lock); 2881185029Spjd return (ENOSYS); 2882185029Spjd } 2883185029Spjd zfs_smbshare_inited = 1; 2884185029Spjd mutex_exit(&zfs_share_lock); 2885185029Spjd } 2886185029Spjd break; 2887185029Spjd default: 2888185029Spjd return (EINVAL); 2889185029Spjd } 2890185029Spjd 2891185029Spjd switch (zc->zc_share.z_sharetype) { 2892185029Spjd case ZFS_SHARE_NFS: 2893185029Spjd case ZFS_UNSHARE_NFS: 2894185029Spjd if (error = 2895185029Spjd znfsexport_fs((void *) 2896185029Spjd (uintptr_t)zc->zc_share.z_exportdata)) 2897185029Spjd return (error); 2898185029Spjd break; 2899185029Spjd case ZFS_SHARE_SMB: 2900185029Spjd case ZFS_UNSHARE_SMB: 2901185029Spjd if (error = zsmbexport_fs((void *) 2902185029Spjd (uintptr_t)zc->zc_share.z_exportdata, 2903185029Spjd zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 2904185029Spjd B_TRUE : B_FALSE)) { 2905185029Spjd return (error); 2906185029Spjd } 2907185029Spjd break; 2908185029Spjd } 2909185029Spjd 2910185029Spjd opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 2911185029Spjd zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 2912185029Spjd SHAREFS_ADD : SHAREFS_REMOVE; 2913185029Spjd 2914185029Spjd /* 2915185029Spjd * Add or remove share from sharetab 2916185029Spjd */ 2917185029Spjd error = zshare_fs(opcode, 2918185029Spjd (void *)(uintptr_t)zc->zc_share.z_sharedata, 2919185029Spjd zc->zc_share.z_sharemax); 2920185029Spjd 2921185029Spjd return (error); 2922185029Spjd#else 2923185029Spjd return (ENOSYS); 2924185029Spjd#endif 2925185029Spjd} 2926185029Spjd 2927185029Spjd/* 2928185029Spjd * pool create, destroy, and export don't log the history as part of 2929185029Spjd * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 2930185029Spjd * do the logging of those commands. 2931185029Spjd */ 2932185029Spjdstatic int 2933168404Spjdzfs_ioc_jail(zfs_cmd_t *zc) 2934168404Spjd{ 2935168404Spjd 2936185029Spjd return (zone_dataset_attach(curthread->td_ucred, zc->zc_name, 2937185029Spjd (int)zc->zc_jailid)); 2938168404Spjd} 2939168404Spjd 2940168404Spjdstatic int 2941168404Spjdzfs_ioc_unjail(zfs_cmd_t *zc) 2942168404Spjd{ 2943168404Spjd 2944185029Spjd return (zone_dataset_detach(curthread->td_ucred, zc->zc_name, 2945185029Spjd (int)zc->zc_jailid)); 2946168404Spjd} 2947168404Spjd 2948168404Spjdstatic zfs_ioc_vec_t zfs_ioc_vec[] = { 2949185029Spjd { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2950185029Spjd { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2951185029Spjd { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2952185029Spjd { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2953185029Spjd { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, 2954185029Spjd { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2955185029Spjd { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2956185029Spjd { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2957185029Spjd { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2958185029Spjd { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2959185029Spjd { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2960185029Spjd { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2961185029Spjd { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2962185029Spjd { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2963185029Spjd { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2964185029Spjd { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2965185029Spjd { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2966185029Spjd { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2967185029Spjd { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2968185029Spjd { zfs_ioc_dataset_list_next, zfs_secpolicy_read, 2969185029Spjd DATASET_NAME, B_FALSE }, 2970185029Spjd { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, 2971185029Spjd DATASET_NAME, B_FALSE }, 2972185029Spjd { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, 2973185029Spjd { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2974185029Spjd { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, 2975185029Spjd { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, 2976185029Spjd { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2977185029Spjd { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, 2978185029Spjd { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, 2979185029Spjd { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, 2980185029Spjd { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, 2981185029Spjd { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2982185029Spjd { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2983185029Spjd { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, 2984185029Spjd { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, 2985185029Spjd { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2986185029Spjd { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, 2987185029Spjd { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, 2988185029Spjd { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, 2989185029Spjd { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, 2990185029Spjd { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, 2991185029Spjd { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, 2992185029Spjd { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, 2993185029Spjd { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, 2994185029Spjd { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, 2995185029Spjd { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, 2996185029Spjd DATASET_NAME, B_FALSE }, 2997185029Spjd { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, 2998185029Spjd { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, 2999185029Spjd { zfs_ioc_jail, zfs_secpolicy_config, DATASET_NAME, B_TRUE }, 3000185029Spjd { zfs_ioc_unjail, zfs_secpolicy_config, DATASET_NAME, B_TRUE } 3001168404Spjd}; 3002168404Spjd 3003168404Spjdstatic int 3004168404Spjdzfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 3005168404Spjd struct thread *td) 3006168404Spjd{ 3007168404Spjd zfs_cmd_t *zc = (void *)addr; 3008168404Spjd uint_t vec; 3009168404Spjd int error; 3010168404Spjd 3011168404Spjd vec = ZFS_IOC(cmd); 3012168404Spjd 3013168404Spjd if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 3014168404Spjd return (EINVAL); 3015168404Spjd 3016185029Spjd error = zfs_ioc_vec[vec].zvec_secpolicy(zc, td->td_ucred); 3017168404Spjd 3018168404Spjd /* 3019168404Spjd * Ensure that all pool/dataset names are valid before we pass down to 3020168404Spjd * the lower layers. 3021168404Spjd */ 3022168404Spjd if (error == 0) { 3023168404Spjd zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 3024168404Spjd switch (zfs_ioc_vec[vec].zvec_namecheck) { 3025185029Spjd case POOL_NAME: 3026168404Spjd if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 3027168404Spjd error = EINVAL; 3028168404Spjd break; 3029168404Spjd 3030185029Spjd case DATASET_NAME: 3031168404Spjd if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 3032168404Spjd error = EINVAL; 3033168404Spjd break; 3034168404Spjd 3035185029Spjd case NO_NAME: 3036168404Spjd break; 3037168404Spjd } 3038168404Spjd } 3039168404Spjd 3040168404Spjd if (error == 0) 3041168404Spjd error = zfs_ioc_vec[vec].zvec_func(zc); 3042168404Spjd 3043196985Spjd if (error == 0) { 3044196985Spjd if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) 3045196985Spjd zfs_log_history(zc); 3046196985Spjd } 3047185029Spjd 3048168404Spjd return (error); 3049168404Spjd} 3050168404Spjd 3051168404Spjd/* 3052168404Spjd * OK, so this is a little weird. 3053168404Spjd * 3054168404Spjd * /dev/zfs is the control node, i.e. minor 0. 3055168404Spjd * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 3056168404Spjd * 3057168404Spjd * /dev/zfs has basically nothing to do except serve up ioctls, 3058168404Spjd * so most of the standard driver entry points are in zvol.c. 3059168404Spjd */ 3060168404Spjdstatic struct cdevsw zfs_cdevsw = { 3061168404Spjd .d_version = D_VERSION, 3062168404Spjd .d_ioctl = zfsdev_ioctl, 3063168404Spjd .d_name = ZFS_DEV_NAME 3064168404Spjd}; 3065168404Spjd 3066168404Spjdstatic void 3067168404Spjdzfsdev_init(void) 3068168404Spjd{ 3069185029Spjd zfsdev = make_dev(&zfs_cdevsw, 0x0, UID_ROOT, GID_OPERATOR, 0666, 3070168404Spjd ZFS_DEV_NAME); 3071168404Spjd} 3072168404Spjd 3073168404Spjdstatic void 3074168404Spjdzfsdev_fini(void) 3075168404Spjd{ 3076168404Spjd if (zfsdev != NULL) 3077168404Spjd destroy_dev(zfsdev); 3078168404Spjd} 3079168404Spjd 3080169929Spjdstatic struct root_hold_token *zfs_root_token; 3081196458Spjdstruct proc *zfsproc; 3082168404Spjd 3083185029Spjduint_t zfs_fsyncer_key; 3084185029Spjdextern uint_t rrw_tsd_key; 3085185029Spjd 3086168404Spjdstatic int 3087168404Spjdzfs_modevent(module_t mod, int type, void *unused __unused) 3088168404Spjd{ 3089196291Spjd int error = 0; 3090168404Spjd 3091168404Spjd switch (type) { 3092168404Spjd case MOD_LOAD: 3093190878Sthompsa zfs_root_token = root_mount_hold("ZFS"); 3094196291Spjd 3095185029Spjd mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 3096196291Spjd 3097196291Spjd spa_init(FREAD | FWRITE); 3098196291Spjd zfs_init(); 3099196291Spjd zvol_init(); 3100196291Spjd 3101196291Spjd tsd_create(&zfs_fsyncer_key, NULL); 3102196291Spjd tsd_create(&rrw_tsd_key, NULL); 3103196291Spjd 3104196291Spjd printf("ZFS storage pool version " SPA_VERSION_STRING "\n"); 3105196291Spjd root_mount_rel(zfs_root_token); 3106196291Spjd 3107196291Spjd zfsdev_init(); 3108168404Spjd break; 3109168404Spjd case MOD_UNLOAD: 3110168775Spjd if (spa_busy() || zfs_busy() || zvol_busy() || 3111168404Spjd zio_injection_enabled) { 3112168404Spjd error = EBUSY; 3113168404Spjd break; 3114168404Spjd } 3115196291Spjd 3116196291Spjd zfsdev_fini(); 3117168404Spjd zvol_fini(); 3118168404Spjd zfs_fini(); 3119168404Spjd spa_fini(); 3120196291Spjd 3121185029Spjd tsd_destroy(&zfs_fsyncer_key); 3122185029Spjd tsd_destroy(&rrw_tsd_key); 3123196291Spjd 3124185029Spjd mutex_destroy(&zfs_share_lock); 3125168404Spjd break; 3126196291Spjd default: 3127196291Spjd error = EOPNOTSUPP; 3128196291Spjd break; 3129168404Spjd } 3130168404Spjd return (error); 3131168404Spjd} 3132168404Spjd 3133168404Spjdstatic moduledata_t zfs_mod = { 3134168404Spjd "zfsctrl", 3135168404Spjd zfs_modevent, 3136168404Spjd 0 3137168404Spjd}; 3138169929SpjdDECLARE_MODULE(zfsctrl, zfs_mod, SI_SUB_VFS, SI_ORDER_ANY); 3139179280SjbMODULE_DEPEND(zfsctrl, opensolaris, 1, 1, 1); 3140193128SkmacyMODULE_DEPEND(zfsctrl, krpc, 1, 1, 1); 3141