zfs_ioctl.c revision 224814
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/* 22219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23168404Spjd */ 24168404Spjd 25168962Spjd#include <sys/types.h> 26168404Spjd#include <sys/param.h> 27168404Spjd#include <sys/systm.h> 28168404Spjd#include <sys/conf.h> 29168404Spjd#include <sys/kernel.h> 30168404Spjd#include <sys/lock.h> 31168404Spjd#include <sys/malloc.h> 32168404Spjd#include <sys/mutex.h> 33168404Spjd#include <sys/proc.h> 34168404Spjd#include <sys/errno.h> 35168404Spjd#include <sys/uio.h> 36168962Spjd#include <sys/buf.h> 37168404Spjd#include <sys/file.h> 38168404Spjd#include <sys/kmem.h> 39168404Spjd#include <sys/conf.h> 40168404Spjd#include <sys/cmn_err.h> 41168404Spjd#include <sys/stat.h> 42168404Spjd#include <sys/zfs_ioctl.h> 43209962Smm#include <sys/zfs_vfsops.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/dmu.h> 50168404Spjd#include <sys/dsl_dir.h> 51168404Spjd#include <sys/dsl_dataset.h> 52168404Spjd#include <sys/dsl_prop.h> 53185029Spjd#include <sys/dsl_deleg.h> 54185029Spjd#include <sys/dmu_objset.h> 55168962Spjd#include <sys/sunddi.h> 56168962Spjd#include <sys/policy.h> 57168962Spjd#include <sys/zone.h> 58168404Spjd#include <sys/nvpair.h> 59168404Spjd#include <sys/mount.h> 60168404Spjd#include <sys/taskqueue.h> 61168404Spjd#include <sys/sdt.h> 62168404Spjd#include <sys/varargs.h> 63168404Spjd#include <sys/fs/zfs.h> 64168404Spjd#include <sys/zfs_ctldir.h> 65185029Spjd#include <sys/zfs_dir.h> 66219089Spjd#include <sys/zfs_onexit.h> 67168404Spjd#include <sys/zvol.h> 68219089Spjd#include <sys/dsl_scan.h> 69185029Spjd#include <sys/dmu_objset.h> 70168404Spjd 71168404Spjd#include "zfs_namecheck.h" 72168404Spjd#include "zfs_prop.h" 73185029Spjd#include "zfs_deleg.h" 74219089Spjd#include "zfs_comutil.h" 75219089Spjd#include "zfs_ioctl_compat.h" 76168404Spjd 77219089SpjdCTASSERT(sizeof(zfs_cmd_t) < IOCPARM_MAX); 78168404Spjd 79168404Spjdstatic struct cdev *zfsdev; 80168404Spjd 81168404Spjdextern void zfs_init(void); 82168404Spjdextern void zfs_fini(void); 83168404Spjd 84168404Spjdtypedef int zfs_ioc_func_t(zfs_cmd_t *); 85185029Spjdtypedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 86168404Spjd 87209962Smmtypedef enum { 88209962Smm NO_NAME, 89209962Smm POOL_NAME, 90209962Smm DATASET_NAME 91209962Smm} zfs_ioc_namecheck_t; 92209962Smm 93168404Spjdtypedef struct zfs_ioc_vec { 94168404Spjd zfs_ioc_func_t *zvec_func; 95168404Spjd zfs_secpolicy_func_t *zvec_secpolicy; 96209962Smm zfs_ioc_namecheck_t zvec_namecheck; 97185029Spjd boolean_t zvec_his_log; 98209962Smm boolean_t zvec_pool_check; 99168404Spjd} zfs_ioc_vec_t; 100168404Spjd 101209962Smm/* This array is indexed by zfs_userquota_prop_t */ 102209962Smmstatic const char *userquota_perms[] = { 103209962Smm ZFS_DELEG_PERM_USERUSED, 104209962Smm ZFS_DELEG_PERM_USERQUOTA, 105209962Smm ZFS_DELEG_PERM_GROUPUSED, 106209962Smm ZFS_DELEG_PERM_GROUPQUOTA, 107209962Smm}; 108209962Smm 109209962Smmstatic int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 110219089Spjdstatic int zfs_check_settable(const char *name, nvpair_t *property, 111219089Spjd cred_t *cr); 112219089Spjdstatic int zfs_check_clearable(char *dataset, nvlist_t *props, 113219089Spjd nvlist_t **errors); 114185029Spjdstatic int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 115185029Spjd boolean_t *); 116219089Spjdint zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t **); 117219089Spjd 118219089Spjdstatic void zfsdev_close(void *data); 119185029Spjd 120168404Spjd/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 121168404Spjdvoid 122168404Spjd__dprintf(const char *file, const char *func, int line, const char *fmt, ...) 123168404Spjd{ 124168404Spjd const char *newfile; 125219089Spjd char buf[512]; 126168404Spjd va_list adx; 127168404Spjd 128168404Spjd /* 129168404Spjd * Get rid of annoying "../common/" prefix to filename. 130168404Spjd */ 131168404Spjd newfile = strrchr(file, '/'); 132168404Spjd if (newfile != NULL) { 133168404Spjd newfile = newfile + 1; /* Get rid of leading / */ 134168404Spjd } else { 135168404Spjd newfile = file; 136168404Spjd } 137168404Spjd 138168404Spjd va_start(adx, fmt); 139168404Spjd (void) vsnprintf(buf, sizeof (buf), fmt, adx); 140168404Spjd va_end(adx); 141168404Spjd 142168404Spjd /* 143168404Spjd * To get this data, use the zfs-dprintf probe as so: 144168404Spjd * dtrace -q -n 'zfs-dprintf \ 145168404Spjd * /stringof(arg0) == "dbuf.c"/ \ 146168404Spjd * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 147168404Spjd * arg0 = file name 148168404Spjd * arg1 = function name 149168404Spjd * arg2 = line number 150168404Spjd * arg3 = message 151168404Spjd */ 152168404Spjd DTRACE_PROBE4(zfs__dprintf, 153168404Spjd char *, newfile, char *, func, int, line, char *, buf); 154168404Spjd} 155168404Spjd 156185029Spjdstatic void 157185029Spjdhistory_str_free(char *buf) 158185029Spjd{ 159185029Spjd kmem_free(buf, HIS_MAX_RECORD_LEN); 160185029Spjd} 161185029Spjd 162185029Spjdstatic char * 163185029Spjdhistory_str_get(zfs_cmd_t *zc) 164185029Spjd{ 165185029Spjd char *buf; 166185029Spjd 167185029Spjd if (zc->zc_history == 0) 168185029Spjd return (NULL); 169185029Spjd 170185029Spjd buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 171185029Spjd if (copyinstr((void *)(uintptr_t)zc->zc_history, 172185029Spjd buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 173185029Spjd history_str_free(buf); 174185029Spjd return (NULL); 175185029Spjd } 176185029Spjd 177185029Spjd buf[HIS_MAX_RECORD_LEN -1] = '\0'; 178185029Spjd 179185029Spjd return (buf); 180185029Spjd} 181185029Spjd 182168404Spjd/* 183185029Spjd * Check to see if the named dataset is currently defined as bootable 184185029Spjd */ 185185029Spjdstatic boolean_t 186185029Spjdzfs_is_bootfs(const char *name) 187185029Spjd{ 188219089Spjd objset_t *os; 189185029Spjd 190219089Spjd if (dmu_objset_hold(name, FTAG, &os) == 0) { 191219089Spjd boolean_t ret; 192219089Spjd ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os))); 193219089Spjd dmu_objset_rele(os, FTAG); 194219089Spjd return (ret); 195185029Spjd } 196219089Spjd return (B_FALSE); 197185029Spjd} 198185029Spjd 199185029Spjd/* 200185029Spjd * zfs_earlier_version 201185029Spjd * 202185029Spjd * Return non-zero if the spa version is less than requested version. 203185029Spjd */ 204185029Spjdstatic int 205185029Spjdzfs_earlier_version(const char *name, int version) 206185029Spjd{ 207185029Spjd spa_t *spa; 208185029Spjd 209185029Spjd if (spa_open(name, &spa, FTAG) == 0) { 210185029Spjd if (spa_version(spa) < version) { 211185029Spjd spa_close(spa, FTAG); 212185029Spjd return (1); 213185029Spjd } 214185029Spjd spa_close(spa, FTAG); 215185029Spjd } 216185029Spjd return (0); 217185029Spjd} 218185029Spjd 219185029Spjd/* 220185029Spjd * zpl_earlier_version 221185029Spjd * 222185029Spjd * Return TRUE if the ZPL version is less than requested version. 223185029Spjd */ 224185029Spjdstatic boolean_t 225185029Spjdzpl_earlier_version(const char *name, int version) 226185029Spjd{ 227185029Spjd objset_t *os; 228185029Spjd boolean_t rc = B_TRUE; 229185029Spjd 230219089Spjd if (dmu_objset_hold(name, FTAG, &os) == 0) { 231185029Spjd uint64_t zplversion; 232185029Spjd 233219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 234219089Spjd dmu_objset_rele(os, FTAG); 235219089Spjd return (B_TRUE); 236219089Spjd } 237219089Spjd /* XXX reading from non-owned objset */ 238185029Spjd if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 239185029Spjd rc = zplversion < version; 240219089Spjd dmu_objset_rele(os, FTAG); 241185029Spjd } 242185029Spjd return (rc); 243185029Spjd} 244185029Spjd 245185029Spjdstatic void 246185029Spjdzfs_log_history(zfs_cmd_t *zc) 247185029Spjd{ 248185029Spjd spa_t *spa; 249185029Spjd char *buf; 250185029Spjd 251185029Spjd if ((buf = history_str_get(zc)) == NULL) 252185029Spjd return; 253185029Spjd 254185029Spjd if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 255185029Spjd if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 256185029Spjd (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 257185029Spjd spa_close(spa, FTAG); 258185029Spjd } 259185029Spjd history_str_free(buf); 260185029Spjd} 261185029Spjd 262185029Spjd/* 263168404Spjd * Policy for top-level read operations (list pools). Requires no privileges, 264168404Spjd * and can be used in the local zone, as there is no associated dataset. 265168404Spjd */ 266168404Spjd/* ARGSUSED */ 267168404Spjdstatic int 268185029Spjdzfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 269168404Spjd{ 270168404Spjd return (0); 271168404Spjd} 272168404Spjd 273168404Spjd/* 274168404Spjd * Policy for dataset read operations (list children, get statistics). Requires 275168404Spjd * no privileges, but must be visible in the local zone. 276168404Spjd */ 277168404Spjd/* ARGSUSED */ 278168404Spjdstatic int 279185029Spjdzfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 280168404Spjd{ 281185029Spjd if (INGLOBALZONE(curthread) || 282185029Spjd zone_dataset_visible(zc->zc_name, NULL)) 283168404Spjd return (0); 284168404Spjd 285168404Spjd return (ENOENT); 286168404Spjd} 287168404Spjd 288168404Spjdstatic int 289219089Spjdzfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr) 290168404Spjd{ 291168404Spjd int writable = 1; 292168404Spjd 293168404Spjd /* 294168404Spjd * The dataset must be visible by this zone -- check this first 295168404Spjd * so they don't see EPERM on something they shouldn't know about. 296168404Spjd */ 297185029Spjd if (!INGLOBALZONE(curthread) && 298168404Spjd !zone_dataset_visible(dataset, &writable)) 299168404Spjd return (ENOENT); 300168404Spjd 301185029Spjd if (INGLOBALZONE(curthread)) { 302168404Spjd /* 303168404Spjd * If the fs is zoned, only root can access it from the 304168404Spjd * global zone. 305168404Spjd */ 306168404Spjd if (secpolicy_zfs(cr) && zoned) 307168404Spjd return (EPERM); 308168404Spjd } else { 309168404Spjd /* 310168404Spjd * If we are in a local zone, the 'zoned' property must be set. 311168404Spjd */ 312168404Spjd if (!zoned) 313168404Spjd return (EPERM); 314168404Spjd 315168404Spjd /* must be writable by this zone */ 316168404Spjd if (!writable) 317168404Spjd return (EPERM); 318168404Spjd } 319168404Spjd return (0); 320168404Spjd} 321168404Spjd 322219089Spjdstatic int 323219089Spjdzfs_dozonecheck(const char *dataset, cred_t *cr) 324219089Spjd{ 325219089Spjd uint64_t zoned; 326219089Spjd 327219089Spjd if (dsl_prop_get_integer(dataset, "jailed", &zoned, NULL)) 328219089Spjd return (ENOENT); 329219089Spjd 330219089Spjd return (zfs_dozonecheck_impl(dataset, zoned, cr)); 331219089Spjd} 332219089Spjd 333219089Spjdstatic int 334219089Spjdzfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr) 335219089Spjd{ 336219089Spjd uint64_t zoned; 337219089Spjd 338219089Spjd rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 339219089Spjd if (dsl_prop_get_ds(ds, "jailed", 8, 1, &zoned, NULL)) { 340219089Spjd rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 341219089Spjd return (ENOENT); 342219089Spjd } 343219089Spjd rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 344219089Spjd 345219089Spjd return (zfs_dozonecheck_impl(dataset, zoned, cr)); 346219089Spjd} 347219089Spjd 348168404Spjdint 349185029Spjdzfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 350168404Spjd{ 351168404Spjd int error; 352168404Spjd 353185029Spjd error = zfs_dozonecheck(name, cr); 354185029Spjd if (error == 0) { 355185029Spjd error = secpolicy_zfs(cr); 356185029Spjd if (error) 357185029Spjd error = dsl_deleg_access(name, perm, cr); 358185029Spjd } 359185029Spjd return (error); 360185029Spjd} 361185029Spjd 362219089Spjdint 363219089Spjdzfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds, 364219089Spjd const char *perm, cred_t *cr) 365219089Spjd{ 366219089Spjd int error; 367219089Spjd 368219089Spjd error = zfs_dozonecheck_ds(name, ds, cr); 369219089Spjd if (error == 0) { 370219089Spjd error = secpolicy_zfs(cr); 371219089Spjd if (error) 372219089Spjd error = dsl_deleg_access_impl(ds, perm, cr); 373219089Spjd } 374219089Spjd return (error); 375219089Spjd} 376219089Spjd 377219089Spjd#ifdef SECLABEL 378219089Spjd/* 379219089Spjd * Policy for setting the security label property. 380219089Spjd * 381219089Spjd * Returns 0 for success, non-zero for access and other errors. 382219089Spjd */ 383185029Spjdstatic int 384219089Spjdzfs_set_slabel_policy(const char *name, char *strval, cred_t *cr) 385185029Spjd{ 386219089Spjd char ds_hexsl[MAXNAMELEN]; 387219089Spjd bslabel_t ds_sl, new_sl; 388219089Spjd boolean_t new_default = FALSE; 389219089Spjd uint64_t zoned; 390219089Spjd int needed_priv = -1; 391219089Spjd int error; 392219089Spjd 393219089Spjd /* First get the existing dataset label. */ 394219089Spjd error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 395219089Spjd 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 396219089Spjd if (error) 397219089Spjd return (EPERM); 398219089Spjd 399219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 400219089Spjd new_default = TRUE; 401219089Spjd 402219089Spjd /* The label must be translatable */ 403219089Spjd if (!new_default && (hexstr_to_label(strval, &new_sl) != 0)) 404219089Spjd return (EINVAL); 405219089Spjd 406185029Spjd /* 407219089Spjd * In a non-global zone, disallow attempts to set a label that 408219089Spjd * doesn't match that of the zone; otherwise no other checks 409219089Spjd * are needed. 410219089Spjd */ 411219089Spjd if (!INGLOBALZONE(curproc)) { 412219089Spjd if (new_default || !blequal(&new_sl, CR_SL(CRED()))) 413219089Spjd return (EPERM); 414219089Spjd return (0); 415219089Spjd } 416219089Spjd 417219089Spjd /* 418219089Spjd * For global-zone datasets (i.e., those whose zoned property is 419219089Spjd * "off", verify that the specified new label is valid for the 420219089Spjd * global zone. 421219089Spjd */ 422219089Spjd if (dsl_prop_get_integer(name, 423219089Spjd zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) 424219089Spjd return (EPERM); 425219089Spjd if (!zoned) { 426219089Spjd if (zfs_check_global_label(name, strval) != 0) 427219089Spjd return (EPERM); 428219089Spjd } 429219089Spjd 430219089Spjd /* 431219089Spjd * If the existing dataset label is nondefault, check if the 432219089Spjd * dataset is mounted (label cannot be changed while mounted). 433219089Spjd * Get the zfsvfs; if there isn't one, then the dataset isn't 434219089Spjd * mounted (or isn't a dataset, doesn't exist, ...). 435219089Spjd */ 436219089Spjd if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) { 437219089Spjd objset_t *os; 438219089Spjd static char *setsl_tag = "setsl_tag"; 439219089Spjd 440219089Spjd /* 441219089Spjd * Try to own the dataset; abort if there is any error, 442219089Spjd * (e.g., already mounted, in use, or other error). 443219089Spjd */ 444219089Spjd error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE, 445219089Spjd setsl_tag, &os); 446219089Spjd if (error) 447219089Spjd return (EPERM); 448219089Spjd 449219089Spjd dmu_objset_disown(os, setsl_tag); 450219089Spjd 451219089Spjd if (new_default) { 452219089Spjd needed_priv = PRIV_FILE_DOWNGRADE_SL; 453219089Spjd goto out_check; 454219089Spjd } 455219089Spjd 456219089Spjd if (hexstr_to_label(strval, &new_sl) != 0) 457219089Spjd return (EPERM); 458219089Spjd 459219089Spjd if (blstrictdom(&ds_sl, &new_sl)) 460219089Spjd needed_priv = PRIV_FILE_DOWNGRADE_SL; 461219089Spjd else if (blstrictdom(&new_sl, &ds_sl)) 462219089Spjd needed_priv = PRIV_FILE_UPGRADE_SL; 463219089Spjd } else { 464219089Spjd /* dataset currently has a default label */ 465219089Spjd if (!new_default) 466219089Spjd needed_priv = PRIV_FILE_UPGRADE_SL; 467219089Spjd } 468219089Spjd 469219089Spjdout_check: 470219089Spjd if (needed_priv != -1) 471219089Spjd return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL)); 472219089Spjd return (0); 473219089Spjd} 474219089Spjd#endif /* SECLABEL */ 475219089Spjd 476219089Spjdstatic int 477219089Spjdzfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval, 478219089Spjd cred_t *cr) 479219089Spjd{ 480219089Spjd char *strval; 481219089Spjd 482219089Spjd /* 483185029Spjd * Check permissions for special properties. 484185029Spjd */ 485185029Spjd switch (prop) { 486185029Spjd case ZFS_PROP_ZONED: 487185029Spjd /* 488185029Spjd * Disallow setting of 'zoned' from within a local zone. 489185029Spjd */ 490185029Spjd if (!INGLOBALZONE(curthread)) 491185029Spjd return (EPERM); 492185029Spjd break; 493185029Spjd 494185029Spjd case ZFS_PROP_QUOTA: 495185029Spjd if (!INGLOBALZONE(curthread)) { 496185029Spjd uint64_t zoned; 497185029Spjd char setpoint[MAXNAMELEN]; 498185029Spjd /* 499185029Spjd * Unprivileged users are allowed to modify the 500185029Spjd * quota on things *under* (ie. contained by) 501185029Spjd * the thing they own. 502185029Spjd */ 503219089Spjd if (dsl_prop_get_integer(dsname, "jailed", &zoned, 504185029Spjd setpoint)) 505185029Spjd return (EPERM); 506219089Spjd if (!zoned || strlen(dsname) <= strlen(setpoint)) 507185029Spjd return (EPERM); 508185029Spjd } 509185029Spjd break; 510219089Spjd 511219089Spjd case ZFS_PROP_MLSLABEL: 512219089Spjd#ifdef SECLABEL 513219089Spjd if (!is_system_labeled()) 514219089Spjd return (EPERM); 515219089Spjd 516219089Spjd if (nvpair_value_string(propval, &strval) == 0) { 517219089Spjd int err; 518219089Spjd 519219089Spjd err = zfs_set_slabel_policy(dsname, strval, CRED()); 520219089Spjd if (err != 0) 521219089Spjd return (err); 522219089Spjd } 523219089Spjd#else 524219089Spjd return (EOPNOTSUPP); 525219089Spjd#endif 526219089Spjd break; 527185029Spjd } 528185029Spjd 529219089Spjd return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr)); 530185029Spjd} 531185029Spjd 532185029Spjdint 533185029Spjdzfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 534185029Spjd{ 535185029Spjd int error; 536185029Spjd 537185029Spjd error = zfs_dozonecheck(zc->zc_name, cr); 538185029Spjd if (error) 539168404Spjd return (error); 540168404Spjd 541185029Spjd /* 542185029Spjd * permission to set permissions will be evaluated later in 543185029Spjd * dsl_deleg_can_allow() 544185029Spjd */ 545185029Spjd return (0); 546168404Spjd} 547168404Spjd 548185029Spjdint 549185029Spjdzfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 550185029Spjd{ 551219089Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 552219089Spjd ZFS_DELEG_PERM_ROLLBACK, cr)); 553185029Spjd} 554185029Spjd 555185029Spjdint 556185029Spjdzfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 557185029Spjd{ 558219089Spjd spa_t *spa; 559219089Spjd dsl_pool_t *dp; 560219089Spjd dsl_dataset_t *ds; 561219089Spjd char *cp; 562219089Spjd int error; 563219089Spjd 564219089Spjd /* 565219089Spjd * Generate the current snapshot name from the given objsetid, then 566219089Spjd * use that name for the secpolicy/zone checks. 567219089Spjd */ 568219089Spjd cp = strchr(zc->zc_name, '@'); 569219089Spjd if (cp == NULL) 570219089Spjd return (EINVAL); 571219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 572219089Spjd if (error) 573219089Spjd return (error); 574219089Spjd 575219089Spjd dp = spa_get_dsl(spa); 576219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 577219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 578219089Spjd rw_exit(&dp->dp_config_rwlock); 579219089Spjd spa_close(spa, FTAG); 580219089Spjd if (error) 581219089Spjd return (error); 582219089Spjd 583219089Spjd dsl_dataset_name(ds, zc->zc_name); 584219089Spjd 585219089Spjd error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds, 586219089Spjd ZFS_DELEG_PERM_SEND, cr); 587219089Spjd dsl_dataset_rele(ds, FTAG); 588219089Spjd 589219089Spjd return (error); 590185029Spjd} 591185029Spjd 592209962Smmstatic int 593209962Smmzfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) 594209962Smm{ 595209962Smm vnode_t *vp; 596209962Smm int error; 597209962Smm 598209962Smm if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 599209962Smm NO_FOLLOW, NULL, &vp)) != 0) 600209962Smm return (error); 601209962Smm 602209962Smm /* Now make sure mntpnt and dataset are ZFS */ 603209962Smm 604209962Smm if (strcmp(vp->v_vfsp->mnt_stat.f_fstypename, "zfs") != 0 || 605209962Smm (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 606209962Smm zc->zc_name) != 0)) { 607209962Smm VN_RELE(vp); 608209962Smm return (EPERM); 609209962Smm } 610209962Smm 611209962Smm VN_RELE(vp); 612209962Smm return (dsl_deleg_access(zc->zc_name, 613209962Smm ZFS_DELEG_PERM_SHARE, cr)); 614209962Smm} 615209962Smm 616185029Spjdint 617185029Spjdzfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 618185029Spjd{ 619185029Spjd if (!INGLOBALZONE(curthread)) 620185029Spjd return (EPERM); 621185029Spjd 622185029Spjd if (secpolicy_nfs(cr) == 0) { 623185029Spjd return (0); 624185029Spjd } else { 625209962Smm return (zfs_secpolicy_deleg_share(zc, cr)); 626209962Smm } 627209962Smm} 628185029Spjd 629209962Smmint 630209962Smmzfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) 631209962Smm{ 632209962Smm if (!INGLOBALZONE(curthread)) 633209962Smm return (EPERM); 634185029Spjd 635209962Smm if (secpolicy_smb(cr) == 0) { 636209962Smm return (0); 637209962Smm } else { 638209962Smm return (zfs_secpolicy_deleg_share(zc, cr)); 639185029Spjd } 640185029Spjd} 641185029Spjd 642168404Spjdstatic int 643185029Spjdzfs_get_parent(const char *datasetname, char *parent, int parentsize) 644168404Spjd{ 645168404Spjd char *cp; 646168404Spjd 647168404Spjd /* 648168404Spjd * Remove the @bla or /bla from the end of the name to get the parent. 649168404Spjd */ 650185029Spjd (void) strncpy(parent, datasetname, parentsize); 651185029Spjd cp = strrchr(parent, '@'); 652168404Spjd if (cp != NULL) { 653168404Spjd cp[0] = '\0'; 654168404Spjd } else { 655185029Spjd cp = strrchr(parent, '/'); 656168404Spjd if (cp == NULL) 657168404Spjd return (ENOENT); 658168404Spjd cp[0] = '\0'; 659185029Spjd } 660168404Spjd 661185029Spjd return (0); 662185029Spjd} 663185029Spjd 664185029Spjdint 665185029Spjdzfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 666185029Spjd{ 667185029Spjd int error; 668185029Spjd 669185029Spjd if ((error = zfs_secpolicy_write_perms(name, 670185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 671185029Spjd return (error); 672185029Spjd 673185029Spjd return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 674185029Spjd} 675185029Spjd 676185029Spjdstatic int 677185029Spjdzfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 678185029Spjd{ 679185029Spjd return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 680185029Spjd} 681185029Spjd 682185029Spjd/* 683219089Spjd * Destroying snapshots with delegated permissions requires 684219089Spjd * descendent mount and destroy permissions. 685219089Spjd * Reassemble the full filesystem@snap name so dsl_deleg_access() 686219089Spjd * can do the correct permission check. 687219089Spjd * 688219089Spjd * Since this routine is used when doing a recursive destroy of snapshots 689219089Spjd * and destroying snapshots requires descendent permissions, a successfull 690219089Spjd * check of the top level snapshot applies to snapshots of all descendent 691219089Spjd * datasets as well. 692222050Smm * 693222050Smm * The top level snapshot may not exist when doing a recursive destroy. 694222050Smm * In this case fallback to permissions of the parent dataset. 695185029Spjd */ 696185029Spjdstatic int 697219089Spjdzfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, cred_t *cr) 698185029Spjd{ 699219089Spjd int error; 700219089Spjd char *dsname; 701219089Spjd 702219089Spjd dsname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value); 703219089Spjd 704219089Spjd error = zfs_secpolicy_destroy_perms(dsname, cr); 705219089Spjd 706222050Smm if (error == ENOENT) 707222050Smm error = zfs_secpolicy_destroy_perms(zc->zc_name, cr); 708222050Smm 709219089Spjd strfree(dsname); 710219089Spjd return (error); 711185029Spjd} 712185029Spjd 713185029Spjdint 714185029Spjdzfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 715185029Spjd{ 716219089Spjd char parentname[MAXNAMELEN]; 717185029Spjd int error; 718185029Spjd 719185029Spjd if ((error = zfs_secpolicy_write_perms(from, 720185029Spjd ZFS_DELEG_PERM_RENAME, cr)) != 0) 721185029Spjd return (error); 722185029Spjd 723185029Spjd if ((error = zfs_secpolicy_write_perms(from, 724185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 725185029Spjd return (error); 726185029Spjd 727185029Spjd if ((error = zfs_get_parent(to, parentname, 728185029Spjd sizeof (parentname))) != 0) 729185029Spjd return (error); 730185029Spjd 731185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 732185029Spjd ZFS_DELEG_PERM_CREATE, cr)) != 0) 733185029Spjd return (error); 734185029Spjd 735185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 736185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 737185029Spjd return (error); 738185029Spjd 739185029Spjd return (error); 740185029Spjd} 741185029Spjd 742185029Spjdstatic int 743185029Spjdzfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 744185029Spjd{ 745185029Spjd return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 746185029Spjd} 747185029Spjd 748185029Spjdstatic int 749185029Spjdzfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 750185029Spjd{ 751219089Spjd char parentname[MAXNAMELEN]; 752185029Spjd objset_t *clone; 753185029Spjd int error; 754185029Spjd 755185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 756185029Spjd ZFS_DELEG_PERM_PROMOTE, cr); 757185029Spjd if (error) 758185029Spjd return (error); 759185029Spjd 760219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &clone); 761185029Spjd 762185029Spjd if (error == 0) { 763185029Spjd dsl_dataset_t *pclone = NULL; 764185029Spjd dsl_dir_t *dd; 765219089Spjd dd = clone->os_dsl_dataset->ds_dir; 766185029Spjd 767185029Spjd rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 768185029Spjd error = dsl_dataset_hold_obj(dd->dd_pool, 769185029Spjd dd->dd_phys->dd_origin_obj, FTAG, &pclone); 770185029Spjd rw_exit(&dd->dd_pool->dp_config_rwlock); 771185029Spjd if (error) { 772219089Spjd dmu_objset_rele(clone, FTAG); 773185029Spjd return (error); 774185029Spjd } 775185029Spjd 776185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 777185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 778185029Spjd 779185029Spjd dsl_dataset_name(pclone, parentname); 780219089Spjd dmu_objset_rele(clone, FTAG); 781185029Spjd dsl_dataset_rele(pclone, FTAG); 782185029Spjd if (error == 0) 783185029Spjd error = zfs_secpolicy_write_perms(parentname, 784185029Spjd ZFS_DELEG_PERM_PROMOTE, cr); 785168404Spjd } 786185029Spjd return (error); 787185029Spjd} 788168404Spjd 789185029Spjdstatic int 790185029Spjdzfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 791185029Spjd{ 792185029Spjd int error; 793185029Spjd 794185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 795185029Spjd ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 796185029Spjd return (error); 797185029Spjd 798185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 799185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 800185029Spjd return (error); 801185029Spjd 802185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 803185029Spjd ZFS_DELEG_PERM_CREATE, cr)); 804168404Spjd} 805168404Spjd 806185029Spjdint 807185029Spjdzfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 808185029Spjd{ 809219089Spjd return (zfs_secpolicy_write_perms(name, 810219089Spjd ZFS_DELEG_PERM_SNAPSHOT, cr)); 811185029Spjd} 812185029Spjd 813185029Spjdstatic int 814185029Spjdzfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 815185029Spjd{ 816185029Spjd 817185029Spjd return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 818185029Spjd} 819185029Spjd 820185029Spjdstatic int 821185029Spjdzfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 822185029Spjd{ 823219089Spjd char parentname[MAXNAMELEN]; 824219089Spjd int error; 825185029Spjd 826185029Spjd if ((error = zfs_get_parent(zc->zc_name, parentname, 827185029Spjd sizeof (parentname))) != 0) 828185029Spjd return (error); 829185029Spjd 830185029Spjd if (zc->zc_value[0] != '\0') { 831185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_value, 832185029Spjd ZFS_DELEG_PERM_CLONE, cr)) != 0) 833185029Spjd return (error); 834185029Spjd } 835185029Spjd 836185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 837185029Spjd ZFS_DELEG_PERM_CREATE, cr)) != 0) 838185029Spjd return (error); 839185029Spjd 840185029Spjd error = zfs_secpolicy_write_perms(parentname, 841185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 842185029Spjd 843185029Spjd return (error); 844185029Spjd} 845185029Spjd 846185029Spjdstatic int 847185029Spjdzfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 848185029Spjd{ 849185029Spjd int error; 850185029Spjd 851185029Spjd error = secpolicy_fs_unmount(cr, NULL); 852185029Spjd if (error) { 853185029Spjd error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 854185029Spjd } 855185029Spjd return (error); 856185029Spjd} 857185029Spjd 858168404Spjd/* 859168404Spjd * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 860168404Spjd * SYS_CONFIG privilege, which is not available in a local zone. 861168404Spjd */ 862168404Spjd/* ARGSUSED */ 863168404Spjdstatic int 864185029Spjdzfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 865168404Spjd{ 866168404Spjd if (secpolicy_sys_config(cr, B_FALSE) != 0) 867168404Spjd return (EPERM); 868168404Spjd 869168404Spjd return (0); 870168404Spjd} 871168404Spjd 872168404Spjd/* 873219089Spjd * Policy for object to name lookups. 874185029Spjd */ 875219089Spjd/* ARGSUSED */ 876185029Spjdstatic int 877219089Spjdzfs_secpolicy_diff(zfs_cmd_t *zc, cred_t *cr) 878185029Spjd{ 879219089Spjd int error; 880185029Spjd 881219089Spjd if ((error = secpolicy_sys_config(cr, B_FALSE)) == 0) 882219089Spjd return (0); 883219089Spjd 884219089Spjd error = zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_DIFF, cr); 885219089Spjd return (error); 886185029Spjd} 887185029Spjd 888185029Spjd/* 889168404Spjd * Policy for fault injection. Requires all privileges. 890168404Spjd */ 891168404Spjd/* ARGSUSED */ 892168404Spjdstatic int 893185029Spjdzfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 894168404Spjd{ 895168404Spjd return (secpolicy_zinject(cr)); 896168404Spjd} 897168404Spjd 898185029Spjdstatic int 899185029Spjdzfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 900185029Spjd{ 901185029Spjd zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 902185029Spjd 903185029Spjd if (prop == ZPROP_INVAL) { 904185029Spjd if (!zfs_prop_user(zc->zc_value)) 905185029Spjd return (EINVAL); 906185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 907185029Spjd ZFS_DELEG_PERM_USERPROP, cr)); 908185029Spjd } else { 909219089Spjd return (zfs_secpolicy_setprop(zc->zc_name, prop, 910219089Spjd NULL, cr)); 911185029Spjd } 912185029Spjd} 913185029Spjd 914168404Spjdstatic int 915209962Smmzfs_secpolicy_userspace_one(zfs_cmd_t *zc, cred_t *cr) 916209962Smm{ 917209962Smm int err = zfs_secpolicy_read(zc, cr); 918209962Smm if (err) 919209962Smm return (err); 920209962Smm 921209962Smm if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 922209962Smm return (EINVAL); 923209962Smm 924209962Smm if (zc->zc_value[0] == 0) { 925209962Smm /* 926209962Smm * They are asking about a posix uid/gid. If it's 927209962Smm * themself, allow it. 928209962Smm */ 929209962Smm if (zc->zc_objset_type == ZFS_PROP_USERUSED || 930209962Smm zc->zc_objset_type == ZFS_PROP_USERQUOTA) { 931209962Smm if (zc->zc_guid == crgetuid(cr)) 932209962Smm return (0); 933209962Smm } else { 934209962Smm if (groupmember(zc->zc_guid, cr)) 935209962Smm return (0); 936209962Smm } 937209962Smm } 938209962Smm 939209962Smm return (zfs_secpolicy_write_perms(zc->zc_name, 940209962Smm userquota_perms[zc->zc_objset_type], cr)); 941209962Smm} 942209962Smm 943209962Smmstatic int 944209962Smmzfs_secpolicy_userspace_many(zfs_cmd_t *zc, cred_t *cr) 945209962Smm{ 946209962Smm int err = zfs_secpolicy_read(zc, cr); 947209962Smm if (err) 948209962Smm return (err); 949209962Smm 950209962Smm if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 951209962Smm return (EINVAL); 952209962Smm 953209962Smm return (zfs_secpolicy_write_perms(zc->zc_name, 954209962Smm userquota_perms[zc->zc_objset_type], cr)); 955209962Smm} 956209962Smm 957209962Smmstatic int 958209962Smmzfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, cred_t *cr) 959209962Smm{ 960219089Spjd return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, 961219089Spjd NULL, cr)); 962209962Smm} 963209962Smm 964219089Spjdstatic int 965219089Spjdzfs_secpolicy_hold(zfs_cmd_t *zc, cred_t *cr) 966219089Spjd{ 967219089Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 968219089Spjd ZFS_DELEG_PERM_HOLD, cr)); 969219089Spjd} 970219089Spjd 971219089Spjdstatic int 972219089Spjdzfs_secpolicy_release(zfs_cmd_t *zc, cred_t *cr) 973219089Spjd{ 974219089Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 975219089Spjd ZFS_DELEG_PERM_RELEASE, cr)); 976219089Spjd} 977219089Spjd 978168404Spjd/* 979219089Spjd * Policy for allowing temporary snapshots to be taken or released 980219089Spjd */ 981219089Spjdstatic int 982219089Spjdzfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, cred_t *cr) 983219089Spjd{ 984219089Spjd /* 985219089Spjd * A temporary snapshot is the same as a snapshot, 986219089Spjd * hold, destroy and release all rolled into one. 987219089Spjd * Delegated diff alone is sufficient that we allow this. 988219089Spjd */ 989219089Spjd int error; 990219089Spjd 991219089Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 992219089Spjd ZFS_DELEG_PERM_DIFF, cr)) == 0) 993219089Spjd return (0); 994219089Spjd 995219089Spjd error = zfs_secpolicy_snapshot(zc, cr); 996219089Spjd if (!error) 997219089Spjd error = zfs_secpolicy_hold(zc, cr); 998219089Spjd if (!error) 999219089Spjd error = zfs_secpolicy_release(zc, cr); 1000219089Spjd if (!error) 1001219089Spjd error = zfs_secpolicy_destroy(zc, cr); 1002219089Spjd return (error); 1003219089Spjd} 1004219089Spjd 1005219089Spjd/* 1006168404Spjd * Returns the nvlist as specified by the user in the zfs_cmd_t. 1007168404Spjd */ 1008168404Spjdstatic int 1009219089Spjdget_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) 1010168404Spjd{ 1011168404Spjd char *packed; 1012168404Spjd int error; 1013185029Spjd nvlist_t *list = NULL; 1014168404Spjd 1015168404Spjd /* 1016168404Spjd * Read in and unpack the user-supplied nvlist. 1017168404Spjd */ 1018185029Spjd if (size == 0) 1019168404Spjd return (EINVAL); 1020168404Spjd 1021168404Spjd packed = kmem_alloc(size, KM_SLEEP); 1022168404Spjd 1023219089Spjd if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 1024219089Spjd iflag)) != 0) { 1025168404Spjd kmem_free(packed, size); 1026168404Spjd return (error); 1027168404Spjd } 1028168404Spjd 1029185029Spjd if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 1030168404Spjd kmem_free(packed, size); 1031168404Spjd return (error); 1032168404Spjd } 1033168404Spjd 1034168404Spjd kmem_free(packed, size); 1035168404Spjd 1036185029Spjd *nvp = list; 1037168404Spjd return (0); 1038168404Spjd} 1039168404Spjd 1040168404Spjdstatic int 1041219089Spjdfit_error_list(zfs_cmd_t *zc, nvlist_t **errors) 1042219089Spjd{ 1043219089Spjd size_t size; 1044219089Spjd 1045219089Spjd VERIFY(nvlist_size(*errors, &size, NV_ENCODE_NATIVE) == 0); 1046219089Spjd 1047219089Spjd if (size > zc->zc_nvlist_dst_size) { 1048219089Spjd nvpair_t *more_errors; 1049219089Spjd int n = 0; 1050219089Spjd 1051219089Spjd if (zc->zc_nvlist_dst_size < 1024) 1052219089Spjd return (ENOMEM); 1053219089Spjd 1054219089Spjd VERIFY(nvlist_add_int32(*errors, ZPROP_N_MORE_ERRORS, 0) == 0); 1055219089Spjd more_errors = nvlist_prev_nvpair(*errors, NULL); 1056219089Spjd 1057219089Spjd do { 1058219089Spjd nvpair_t *pair = nvlist_prev_nvpair(*errors, 1059219089Spjd more_errors); 1060219089Spjd VERIFY(nvlist_remove_nvpair(*errors, pair) == 0); 1061219089Spjd n++; 1062219089Spjd VERIFY(nvlist_size(*errors, &size, 1063219089Spjd NV_ENCODE_NATIVE) == 0); 1064219089Spjd } while (size > zc->zc_nvlist_dst_size); 1065219089Spjd 1066219089Spjd VERIFY(nvlist_remove_nvpair(*errors, more_errors) == 0); 1067219089Spjd VERIFY(nvlist_add_int32(*errors, ZPROP_N_MORE_ERRORS, n) == 0); 1068219089Spjd ASSERT(nvlist_size(*errors, &size, NV_ENCODE_NATIVE) == 0); 1069219089Spjd ASSERT(size <= zc->zc_nvlist_dst_size); 1070219089Spjd } 1071219089Spjd 1072219089Spjd return (0); 1073219089Spjd} 1074219089Spjd 1075219089Spjdstatic int 1076168404Spjdput_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 1077168404Spjd{ 1078168404Spjd char *packed = NULL; 1079219089Spjd int error = 0; 1080168404Spjd size_t size; 1081168404Spjd 1082168404Spjd VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 1083168404Spjd 1084168404Spjd if (size > zc->zc_nvlist_dst_size) { 1085168404Spjd /* 1086168404Spjd * Solaris returns ENOMEM here, because even if an error is 1087168404Spjd * returned from an ioctl(2), new zc_nvlist_dst_size will be 1088168404Spjd * passed to the userland. This is not the case for FreeBSD. 1089168404Spjd * We need to return 0, so the kernel will copy the 1090168404Spjd * zc_nvlist_dst_size back and the userland can discover that a 1091168404Spjd * bigger buffer is needed. 1092168404Spjd */ 1093168404Spjd error = 0; 1094168404Spjd } else { 1095185029Spjd packed = kmem_alloc(size, KM_SLEEP); 1096168404Spjd VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 1097168404Spjd KM_SLEEP) == 0); 1098219089Spjd if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 1099219089Spjd size, zc->zc_iflags) != 0) 1100219089Spjd error = EFAULT; 1101168404Spjd kmem_free(packed, size); 1102168404Spjd } 1103168404Spjd 1104168404Spjd zc->zc_nvlist_dst_size = size; 1105168404Spjd return (error); 1106168404Spjd} 1107168404Spjd 1108168404Spjdstatic int 1109219089Spjdgetzfsvfs(const char *dsname, zfsvfs_t **zfvp) 1110209962Smm{ 1111209962Smm objset_t *os; 1112209962Smm int error; 1113209962Smm 1114219089Spjd error = dmu_objset_hold(dsname, FTAG, &os); 1115209962Smm if (error) 1116209962Smm return (error); 1117219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 1118219089Spjd dmu_objset_rele(os, FTAG); 1119219089Spjd return (EINVAL); 1120219089Spjd } 1121209962Smm 1122219089Spjd mutex_enter(&os->os_user_ptr_lock); 1123219089Spjd *zfvp = dmu_objset_get_user(os); 1124219089Spjd if (*zfvp) { 1125219089Spjd VFS_HOLD((*zfvp)->z_vfs); 1126209962Smm } else { 1127209962Smm error = ESRCH; 1128209962Smm } 1129219089Spjd mutex_exit(&os->os_user_ptr_lock); 1130219089Spjd dmu_objset_rele(os, FTAG); 1131209962Smm return (error); 1132209962Smm} 1133209962Smm 1134209962Smm/* 1135209962Smm * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 1136209962Smm * case its z_vfs will be NULL, and it will be opened as the owner. 1137209962Smm */ 1138209962Smmstatic int 1139219089Spjdzfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer) 1140209962Smm{ 1141209962Smm int error = 0; 1142209962Smm 1143219089Spjd if (getzfsvfs(name, zfvp) != 0) 1144219089Spjd error = zfsvfs_create(name, zfvp); 1145209962Smm if (error == 0) { 1146219089Spjd rrw_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER : 1147219089Spjd RW_READER, tag); 1148219089Spjd if ((*zfvp)->z_unmounted) { 1149209962Smm /* 1150209962Smm * XXX we could probably try again, since the unmounting 1151209962Smm * thread should be just about to disassociate the 1152209962Smm * objset from the zfsvfs. 1153209962Smm */ 1154219089Spjd rrw_exit(&(*zfvp)->z_teardown_lock, tag); 1155209962Smm return (EBUSY); 1156209962Smm } 1157209962Smm } 1158209962Smm return (error); 1159209962Smm} 1160209962Smm 1161209962Smmstatic void 1162209962Smmzfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 1163209962Smm{ 1164209962Smm rrw_exit(&zfsvfs->z_teardown_lock, tag); 1165209962Smm 1166209962Smm if (zfsvfs->z_vfs) { 1167209962Smm VFS_RELE(zfsvfs->z_vfs); 1168209962Smm } else { 1169219089Spjd dmu_objset_disown(zfsvfs->z_os, zfsvfs); 1170209962Smm zfsvfs_free(zfsvfs); 1171209962Smm } 1172209962Smm} 1173209962Smm 1174209962Smmstatic int 1175168404Spjdzfs_ioc_pool_create(zfs_cmd_t *zc) 1176168404Spjd{ 1177168404Spjd int error; 1178185029Spjd nvlist_t *config, *props = NULL; 1179185029Spjd nvlist_t *rootprops = NULL; 1180185029Spjd nvlist_t *zplprops = NULL; 1181185029Spjd char *buf; 1182168404Spjd 1183185029Spjd if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1184219089Spjd zc->zc_iflags, &config)) 1185168404Spjd return (error); 1186168404Spjd 1187185029Spjd if (zc->zc_nvlist_src_size != 0 && (error = 1188219089Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1189219089Spjd zc->zc_iflags, &props))) { 1190185029Spjd nvlist_free(config); 1191185029Spjd return (error); 1192185029Spjd } 1193168404Spjd 1194185029Spjd if (props) { 1195185029Spjd nvlist_t *nvl = NULL; 1196185029Spjd uint64_t version = SPA_VERSION; 1197185029Spjd 1198185029Spjd (void) nvlist_lookup_uint64(props, 1199185029Spjd zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 1200185029Spjd if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) { 1201185029Spjd error = EINVAL; 1202185029Spjd goto pool_props_bad; 1203185029Spjd } 1204185029Spjd (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 1205185029Spjd if (nvl) { 1206185029Spjd error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 1207185029Spjd if (error != 0) { 1208185029Spjd nvlist_free(config); 1209185029Spjd nvlist_free(props); 1210185029Spjd return (error); 1211185029Spjd } 1212185029Spjd (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 1213185029Spjd } 1214185029Spjd VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1215185029Spjd error = zfs_fill_zplprops_root(version, rootprops, 1216185029Spjd zplprops, NULL); 1217185029Spjd if (error) 1218185029Spjd goto pool_props_bad; 1219185029Spjd } 1220185029Spjd 1221185029Spjd buf = history_str_get(zc); 1222185029Spjd 1223185029Spjd error = spa_create(zc->zc_name, config, props, buf, zplprops); 1224185029Spjd 1225185029Spjd /* 1226185029Spjd * Set the remaining root properties 1227185029Spjd */ 1228219089Spjd if (!error && (error = zfs_set_prop_nvlist(zc->zc_name, 1229219089Spjd ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) 1230185029Spjd (void) spa_destroy(zc->zc_name); 1231185029Spjd 1232185029Spjd if (buf != NULL) 1233185029Spjd history_str_free(buf); 1234185029Spjd 1235185029Spjdpool_props_bad: 1236185029Spjd nvlist_free(rootprops); 1237185029Spjd nvlist_free(zplprops); 1238168404Spjd nvlist_free(config); 1239185029Spjd nvlist_free(props); 1240168404Spjd 1241168404Spjd return (error); 1242168404Spjd} 1243168404Spjd 1244168404Spjdstatic int 1245168404Spjdzfs_ioc_pool_destroy(zfs_cmd_t *zc) 1246168404Spjd{ 1247185029Spjd int error; 1248185029Spjd zfs_log_history(zc); 1249185029Spjd error = spa_destroy(zc->zc_name); 1250219089Spjd if (error == 0) 1251219089Spjd zvol_remove_minors(zc->zc_name); 1252185029Spjd return (error); 1253168404Spjd} 1254168404Spjd 1255168404Spjdstatic int 1256168404Spjdzfs_ioc_pool_import(zfs_cmd_t *zc) 1257168404Spjd{ 1258185029Spjd nvlist_t *config, *props = NULL; 1259168404Spjd uint64_t guid; 1260219089Spjd int error; 1261168404Spjd 1262185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1263219089Spjd zc->zc_iflags, &config)) != 0) 1264168404Spjd return (error); 1265168404Spjd 1266185029Spjd if (zc->zc_nvlist_src_size != 0 && (error = 1267219089Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1268219089Spjd zc->zc_iflags, &props))) { 1269185029Spjd nvlist_free(config); 1270185029Spjd return (error); 1271185029Spjd } 1272185029Spjd 1273168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 1274168404Spjd guid != zc->zc_guid) 1275168404Spjd error = EINVAL; 1276168404Spjd else 1277219089Spjd error = spa_import(zc->zc_name, config, props, zc->zc_cookie); 1278168404Spjd 1279219089Spjd if (zc->zc_nvlist_dst != 0) { 1280219089Spjd int err; 1281219089Spjd 1282219089Spjd if ((err = put_nvlist(zc, config)) != 0) 1283219089Spjd error = err; 1284219089Spjd } 1285219089Spjd 1286168404Spjd nvlist_free(config); 1287168404Spjd 1288185029Spjd if (props) 1289185029Spjd nvlist_free(props); 1290185029Spjd 1291168404Spjd return (error); 1292168404Spjd} 1293168404Spjd 1294168404Spjdstatic int 1295168404Spjdzfs_ioc_pool_export(zfs_cmd_t *zc) 1296168404Spjd{ 1297185029Spjd int error; 1298185029Spjd boolean_t force = (boolean_t)zc->zc_cookie; 1299207670Smm boolean_t hardforce = (boolean_t)zc->zc_guid; 1300185029Spjd 1301185029Spjd zfs_log_history(zc); 1302207670Smm error = spa_export(zc->zc_name, NULL, force, hardforce); 1303219089Spjd if (error == 0) 1304219089Spjd zvol_remove_minors(zc->zc_name); 1305185029Spjd return (error); 1306168404Spjd} 1307168404Spjd 1308168404Spjdstatic int 1309168404Spjdzfs_ioc_pool_configs(zfs_cmd_t *zc) 1310168404Spjd{ 1311168404Spjd nvlist_t *configs; 1312168404Spjd int error; 1313168404Spjd 1314168404Spjd if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1315168404Spjd return (EEXIST); 1316168404Spjd 1317168404Spjd error = put_nvlist(zc, configs); 1318168404Spjd 1319168404Spjd nvlist_free(configs); 1320168404Spjd 1321168404Spjd return (error); 1322168404Spjd} 1323168404Spjd 1324168404Spjdstatic int 1325168404Spjdzfs_ioc_pool_stats(zfs_cmd_t *zc) 1326168404Spjd{ 1327168404Spjd nvlist_t *config; 1328168404Spjd int error; 1329168404Spjd int ret = 0; 1330168404Spjd 1331168404Spjd error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 1332168404Spjd sizeof (zc->zc_value)); 1333168404Spjd 1334168404Spjd if (config != NULL) { 1335168404Spjd ret = put_nvlist(zc, config); 1336168404Spjd nvlist_free(config); 1337168404Spjd 1338168404Spjd /* 1339168404Spjd * The config may be present even if 'error' is non-zero. 1340168404Spjd * In this case we return success, and preserve the real errno 1341168404Spjd * in 'zc_cookie'. 1342168404Spjd */ 1343168404Spjd zc->zc_cookie = error; 1344168404Spjd } else { 1345168404Spjd ret = error; 1346168404Spjd } 1347168404Spjd 1348168404Spjd return (ret); 1349168404Spjd} 1350168404Spjd 1351168404Spjd/* 1352168404Spjd * Try to import the given pool, returning pool stats as appropriate so that 1353168404Spjd * user land knows which devices are available and overall pool health. 1354168404Spjd */ 1355168404Spjdstatic int 1356168404Spjdzfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1357168404Spjd{ 1358168404Spjd nvlist_t *tryconfig, *config; 1359168404Spjd int error; 1360168404Spjd 1361185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1362219089Spjd zc->zc_iflags, &tryconfig)) != 0) 1363168404Spjd return (error); 1364168404Spjd 1365168404Spjd config = spa_tryimport(tryconfig); 1366168404Spjd 1367168404Spjd nvlist_free(tryconfig); 1368168404Spjd 1369168404Spjd if (config == NULL) 1370168404Spjd return (EINVAL); 1371168404Spjd 1372168404Spjd error = put_nvlist(zc, config); 1373168404Spjd nvlist_free(config); 1374168404Spjd 1375168404Spjd return (error); 1376168404Spjd} 1377168404Spjd 1378219089Spjd/* 1379219089Spjd * inputs: 1380219089Spjd * zc_name name of the pool 1381219089Spjd * zc_cookie scan func (pool_scan_func_t) 1382219089Spjd */ 1383168404Spjdstatic int 1384219089Spjdzfs_ioc_pool_scan(zfs_cmd_t *zc) 1385168404Spjd{ 1386168404Spjd spa_t *spa; 1387168404Spjd int error; 1388168404Spjd 1389168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1390168404Spjd return (error); 1391168404Spjd 1392219089Spjd if (zc->zc_cookie == POOL_SCAN_NONE) 1393219089Spjd error = spa_scan_stop(spa); 1394219089Spjd else 1395219089Spjd error = spa_scan(spa, zc->zc_cookie); 1396168404Spjd 1397168404Spjd spa_close(spa, FTAG); 1398168404Spjd 1399168404Spjd return (error); 1400168404Spjd} 1401168404Spjd 1402168404Spjdstatic int 1403168404Spjdzfs_ioc_pool_freeze(zfs_cmd_t *zc) 1404168404Spjd{ 1405168404Spjd spa_t *spa; 1406168404Spjd int error; 1407168404Spjd 1408168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1409168404Spjd if (error == 0) { 1410168404Spjd spa_freeze(spa); 1411168404Spjd spa_close(spa, FTAG); 1412168404Spjd } 1413168404Spjd return (error); 1414168404Spjd} 1415168404Spjd 1416168404Spjdstatic int 1417168404Spjdzfs_ioc_pool_upgrade(zfs_cmd_t *zc) 1418168404Spjd{ 1419168404Spjd spa_t *spa; 1420168404Spjd int error; 1421168404Spjd 1422168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1423168404Spjd return (error); 1424168404Spjd 1425185029Spjd if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { 1426185029Spjd spa_close(spa, FTAG); 1427185029Spjd return (EINVAL); 1428185029Spjd } 1429168404Spjd 1430185029Spjd spa_upgrade(spa, zc->zc_cookie); 1431168404Spjd spa_close(spa, FTAG); 1432168404Spjd 1433168404Spjd return (error); 1434168404Spjd} 1435168404Spjd 1436168404Spjdstatic int 1437168404Spjdzfs_ioc_pool_get_history(zfs_cmd_t *zc) 1438168404Spjd{ 1439168404Spjd spa_t *spa; 1440168404Spjd char *hist_buf; 1441168404Spjd uint64_t size; 1442168404Spjd int error; 1443168404Spjd 1444168404Spjd if ((size = zc->zc_history_len) == 0) 1445168404Spjd return (EINVAL); 1446168404Spjd 1447168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1448168404Spjd return (error); 1449168404Spjd 1450185029Spjd if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1451168404Spjd spa_close(spa, FTAG); 1452168404Spjd return (ENOTSUP); 1453168404Spjd } 1454168404Spjd 1455168404Spjd hist_buf = kmem_alloc(size, KM_SLEEP); 1456168404Spjd if ((error = spa_history_get(spa, &zc->zc_history_offset, 1457168404Spjd &zc->zc_history_len, hist_buf)) == 0) { 1458219089Spjd error = ddi_copyout(hist_buf, 1459219089Spjd (void *)(uintptr_t)zc->zc_history, 1460219089Spjd zc->zc_history_len, zc->zc_iflags); 1461168404Spjd } 1462168404Spjd 1463168404Spjd spa_close(spa, FTAG); 1464168404Spjd kmem_free(hist_buf, size); 1465168404Spjd return (error); 1466168404Spjd} 1467168404Spjd 1468168404Spjdstatic int 1469168404Spjdzfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 1470168404Spjd{ 1471168404Spjd int error; 1472168404Spjd 1473168404Spjd if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 1474168404Spjd return (error); 1475168404Spjd 1476168404Spjd return (0); 1477168404Spjd} 1478168404Spjd 1479219089Spjd/* 1480219089Spjd * inputs: 1481219089Spjd * zc_name name of filesystem 1482219089Spjd * zc_obj object to find 1483219089Spjd * 1484219089Spjd * outputs: 1485219089Spjd * zc_value name of object 1486219089Spjd */ 1487168404Spjdstatic int 1488168404Spjdzfs_ioc_obj_to_path(zfs_cmd_t *zc) 1489168404Spjd{ 1490219089Spjd objset_t *os; 1491168404Spjd int error; 1492168404Spjd 1493219089Spjd /* XXX reading from objset not owned */ 1494219089Spjd if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0) 1495168404Spjd return (error); 1496219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 1497219089Spjd dmu_objset_rele(os, FTAG); 1498219089Spjd return (EINVAL); 1499219089Spjd } 1500219089Spjd error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value, 1501168404Spjd sizeof (zc->zc_value)); 1502219089Spjd dmu_objset_rele(os, FTAG); 1503168404Spjd 1504168404Spjd return (error); 1505168404Spjd} 1506168404Spjd 1507219089Spjd/* 1508219089Spjd * inputs: 1509219089Spjd * zc_name name of filesystem 1510219089Spjd * zc_obj object to find 1511219089Spjd * 1512219089Spjd * outputs: 1513219089Spjd * zc_stat stats on object 1514219089Spjd * zc_value path to object 1515219089Spjd */ 1516168404Spjdstatic int 1517219089Spjdzfs_ioc_obj_to_stats(zfs_cmd_t *zc) 1518219089Spjd{ 1519219089Spjd objset_t *os; 1520219089Spjd int error; 1521219089Spjd 1522219089Spjd /* XXX reading from objset not owned */ 1523219089Spjd if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0) 1524219089Spjd return (error); 1525219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 1526219089Spjd dmu_objset_rele(os, FTAG); 1527219089Spjd return (EINVAL); 1528219089Spjd } 1529219089Spjd error = zfs_obj_to_stats(os, zc->zc_obj, &zc->zc_stat, zc->zc_value, 1530219089Spjd sizeof (zc->zc_value)); 1531219089Spjd dmu_objset_rele(os, FTAG); 1532219089Spjd 1533219089Spjd return (error); 1534219089Spjd} 1535219089Spjd 1536219089Spjdstatic int 1537168404Spjdzfs_ioc_vdev_add(zfs_cmd_t *zc) 1538168404Spjd{ 1539168404Spjd spa_t *spa; 1540168404Spjd int error; 1541185029Spjd nvlist_t *config, **l2cache, **spares; 1542185029Spjd uint_t nl2cache = 0, nspares = 0; 1543168404Spjd 1544168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1545168404Spjd if (error != 0) 1546168404Spjd return (error); 1547168404Spjd 1548185029Spjd error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1549219089Spjd zc->zc_iflags, &config); 1550185029Spjd (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1551185029Spjd &l2cache, &nl2cache); 1552185029Spjd 1553185029Spjd (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1554185029Spjd &spares, &nspares); 1555185029Spjd 1556168404Spjd /* 1557168404Spjd * A root pool with concatenated devices is not supported. 1558185029Spjd * Thus, can not add a device to a root pool. 1559185029Spjd * 1560185029Spjd * Intent log device can not be added to a rootpool because 1561185029Spjd * during mountroot, zil is replayed, a seperated log device 1562185029Spjd * can not be accessed during the mountroot time. 1563185029Spjd * 1564185029Spjd * l2cache and spare devices are ok to be added to a rootpool. 1565168404Spjd */ 1566219089Spjd if (spa_bootfs(spa) != 0 && nl2cache == 0 && nspares == 0) { 1567219089Spjd nvlist_free(config); 1568168404Spjd spa_close(spa, FTAG); 1569168404Spjd return (EDOM); 1570168404Spjd } 1571168404Spjd 1572185029Spjd if (error == 0) { 1573168404Spjd error = spa_vdev_add(spa, config); 1574168404Spjd nvlist_free(config); 1575168404Spjd } 1576168404Spjd spa_close(spa, FTAG); 1577168404Spjd return (error); 1578168404Spjd} 1579168404Spjd 1580219089Spjd/* 1581219089Spjd * inputs: 1582219089Spjd * zc_name name of the pool 1583219089Spjd * zc_nvlist_conf nvlist of devices to remove 1584219089Spjd * zc_cookie to stop the remove? 1585219089Spjd */ 1586168404Spjdstatic int 1587168404Spjdzfs_ioc_vdev_remove(zfs_cmd_t *zc) 1588168404Spjd{ 1589168404Spjd spa_t *spa; 1590168404Spjd int error; 1591168404Spjd 1592168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1593168404Spjd if (error != 0) 1594168404Spjd return (error); 1595168404Spjd error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 1596168404Spjd spa_close(spa, FTAG); 1597168404Spjd return (error); 1598168404Spjd} 1599168404Spjd 1600168404Spjdstatic int 1601185029Spjdzfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1602168404Spjd{ 1603168404Spjd spa_t *spa; 1604168404Spjd int error; 1605185029Spjd vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1606168404Spjd 1607168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1608168404Spjd return (error); 1609185029Spjd switch (zc->zc_cookie) { 1610185029Spjd case VDEV_STATE_ONLINE: 1611185029Spjd error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 1612185029Spjd break; 1613168404Spjd 1614185029Spjd case VDEV_STATE_OFFLINE: 1615185029Spjd error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 1616185029Spjd break; 1617168404Spjd 1618185029Spjd case VDEV_STATE_FAULTED: 1619219089Spjd if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1620219089Spjd zc->zc_obj != VDEV_AUX_EXTERNAL) 1621219089Spjd zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1622219089Spjd 1623219089Spjd error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); 1624185029Spjd break; 1625185029Spjd 1626185029Spjd case VDEV_STATE_DEGRADED: 1627219089Spjd if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1628219089Spjd zc->zc_obj != VDEV_AUX_EXTERNAL) 1629219089Spjd zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1630219089Spjd 1631219089Spjd error = vdev_degrade(spa, zc->zc_guid, zc->zc_obj); 1632185029Spjd break; 1633185029Spjd 1634185029Spjd default: 1635185029Spjd error = EINVAL; 1636185029Spjd } 1637185029Spjd zc->zc_cookie = newstate; 1638168404Spjd spa_close(spa, FTAG); 1639168404Spjd return (error); 1640168404Spjd} 1641168404Spjd 1642168404Spjdstatic int 1643168404Spjdzfs_ioc_vdev_attach(zfs_cmd_t *zc) 1644168404Spjd{ 1645168404Spjd spa_t *spa; 1646168404Spjd int replacing = zc->zc_cookie; 1647168404Spjd nvlist_t *config; 1648168404Spjd int error; 1649168404Spjd 1650168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1651168404Spjd return (error); 1652168404Spjd 1653185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1654219089Spjd zc->zc_iflags, &config)) == 0) { 1655168404Spjd error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1656168404Spjd nvlist_free(config); 1657168404Spjd } 1658168404Spjd 1659168404Spjd spa_close(spa, FTAG); 1660168404Spjd return (error); 1661168404Spjd} 1662168404Spjd 1663168404Spjdstatic int 1664168404Spjdzfs_ioc_vdev_detach(zfs_cmd_t *zc) 1665168404Spjd{ 1666168404Spjd spa_t *spa; 1667168404Spjd int error; 1668168404Spjd 1669168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1670168404Spjd return (error); 1671168404Spjd 1672209962Smm error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 1673168404Spjd 1674168404Spjd spa_close(spa, FTAG); 1675168404Spjd return (error); 1676168404Spjd} 1677168404Spjd 1678168404Spjdstatic int 1679219089Spjdzfs_ioc_vdev_split(zfs_cmd_t *zc) 1680219089Spjd{ 1681219089Spjd spa_t *spa; 1682219089Spjd nvlist_t *config, *props = NULL; 1683219089Spjd int error; 1684219089Spjd boolean_t exp = !!(zc->zc_cookie & ZPOOL_EXPORT_AFTER_SPLIT); 1685219089Spjd 1686219089Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1687219089Spjd return (error); 1688219089Spjd 1689219089Spjd if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1690219089Spjd zc->zc_iflags, &config)) { 1691219089Spjd spa_close(spa, FTAG); 1692219089Spjd return (error); 1693219089Spjd } 1694219089Spjd 1695219089Spjd if (zc->zc_nvlist_src_size != 0 && (error = 1696219089Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1697219089Spjd zc->zc_iflags, &props))) { 1698219089Spjd spa_close(spa, FTAG); 1699219089Spjd nvlist_free(config); 1700219089Spjd return (error); 1701219089Spjd } 1702219089Spjd 1703219089Spjd error = spa_vdev_split_mirror(spa, zc->zc_string, config, props, exp); 1704219089Spjd 1705219089Spjd spa_close(spa, FTAG); 1706219089Spjd 1707219089Spjd nvlist_free(config); 1708219089Spjd nvlist_free(props); 1709219089Spjd 1710219089Spjd return (error); 1711219089Spjd} 1712219089Spjd 1713219089Spjdstatic int 1714168404Spjdzfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1715168404Spjd{ 1716168404Spjd spa_t *spa; 1717168404Spjd char *path = zc->zc_value; 1718168404Spjd uint64_t guid = zc->zc_guid; 1719168404Spjd int error; 1720168404Spjd 1721168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1722168404Spjd if (error != 0) 1723168404Spjd return (error); 1724168404Spjd 1725168404Spjd error = spa_vdev_setpath(spa, guid, path); 1726168404Spjd spa_close(spa, FTAG); 1727168404Spjd return (error); 1728168404Spjd} 1729168404Spjd 1730209962Smmstatic int 1731209962Smmzfs_ioc_vdev_setfru(zfs_cmd_t *zc) 1732209962Smm{ 1733209962Smm spa_t *spa; 1734209962Smm char *fru = zc->zc_value; 1735209962Smm uint64_t guid = zc->zc_guid; 1736209962Smm int error; 1737209962Smm 1738209962Smm error = spa_open(zc->zc_name, &spa, FTAG); 1739209962Smm if (error != 0) 1740209962Smm return (error); 1741209962Smm 1742209962Smm error = spa_vdev_setfru(spa, guid, fru); 1743209962Smm spa_close(spa, FTAG); 1744209962Smm return (error); 1745209962Smm} 1746209962Smm 1747219089Spjdstatic int 1748219089Spjdzfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) 1749219089Spjd{ 1750219089Spjd int error = 0; 1751219089Spjd nvlist_t *nv; 1752219089Spjd 1753219089Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1754219089Spjd 1755219089Spjd if (zc->zc_nvlist_dst != 0 && 1756219089Spjd (error = dsl_prop_get_all(os, &nv)) == 0) { 1757219089Spjd dmu_objset_stats(os, nv); 1758219089Spjd /* 1759219089Spjd * NB: zvol_get_stats() will read the objset contents, 1760219089Spjd * which we aren't supposed to do with a 1761219089Spjd * DS_MODE_USER hold, because it could be 1762219089Spjd * inconsistent. So this is a bit of a workaround... 1763219089Spjd * XXX reading with out owning 1764219089Spjd */ 1765219089Spjd if (!zc->zc_objset_stats.dds_inconsistent) { 1766219089Spjd if (dmu_objset_type(os) == DMU_OST_ZVOL) 1767219089Spjd VERIFY(zvol_get_stats(os, nv) == 0); 1768219089Spjd } 1769219089Spjd error = put_nvlist(zc, nv); 1770219089Spjd nvlist_free(nv); 1771219089Spjd } 1772219089Spjd 1773219089Spjd return (error); 1774219089Spjd} 1775219089Spjd 1776185029Spjd/* 1777185029Spjd * inputs: 1778185029Spjd * zc_name name of filesystem 1779185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1780185029Spjd * 1781185029Spjd * outputs: 1782185029Spjd * zc_objset_stats stats 1783185029Spjd * zc_nvlist_dst property nvlist 1784185029Spjd * zc_nvlist_dst_size size of property nvlist 1785185029Spjd */ 1786168404Spjdstatic int 1787168404Spjdzfs_ioc_objset_stats(zfs_cmd_t *zc) 1788168404Spjd{ 1789168404Spjd objset_t *os = NULL; 1790168404Spjd int error; 1791219089Spjd 1792219089Spjd if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1793219089Spjd return (error); 1794219089Spjd 1795219089Spjd error = zfs_ioc_objset_stats_impl(zc, os); 1796219089Spjd 1797219089Spjd dmu_objset_rele(os, FTAG); 1798219089Spjd 1799219089Spjd if (error == ENOMEM) 1800219089Spjd error = 0; 1801219089Spjd return (error); 1802219089Spjd} 1803219089Spjd 1804219089Spjd/* 1805219089Spjd * inputs: 1806219089Spjd * zc_name name of filesystem 1807219089Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1808219089Spjd * 1809219089Spjd * outputs: 1810219089Spjd * zc_nvlist_dst received property nvlist 1811219089Spjd * zc_nvlist_dst_size size of received property nvlist 1812219089Spjd * 1813219089Spjd * Gets received properties (distinct from local properties on or after 1814219089Spjd * SPA_VERSION_RECVD_PROPS) for callers who want to differentiate received from 1815219089Spjd * local property values. 1816219089Spjd */ 1817219089Spjdstatic int 1818219089Spjdzfs_ioc_objset_recvd_props(zfs_cmd_t *zc) 1819219089Spjd{ 1820219089Spjd objset_t *os = NULL; 1821219089Spjd int error; 1822168404Spjd nvlist_t *nv; 1823168404Spjd 1824219089Spjd if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1825168404Spjd return (error); 1826168404Spjd 1827219089Spjd /* 1828219089Spjd * Without this check, we would return local property values if the 1829219089Spjd * caller has not already received properties on or after 1830219089Spjd * SPA_VERSION_RECVD_PROPS. 1831219089Spjd */ 1832219089Spjd if (!dsl_prop_get_hasrecvd(os)) { 1833219089Spjd dmu_objset_rele(os, FTAG); 1834219089Spjd return (ENOTSUP); 1835219089Spjd } 1836168404Spjd 1837168404Spjd if (zc->zc_nvlist_dst != 0 && 1838219089Spjd (error = dsl_prop_get_received(os, &nv)) == 0) { 1839168404Spjd error = put_nvlist(zc, nv); 1840168404Spjd nvlist_free(nv); 1841168404Spjd } 1842168404Spjd 1843219089Spjd dmu_objset_rele(os, FTAG); 1844168404Spjd return (error); 1845168404Spjd} 1846168404Spjd 1847168404Spjdstatic int 1848185029Spjdnvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1849185029Spjd{ 1850185029Spjd uint64_t value; 1851185029Spjd int error; 1852185029Spjd 1853185029Spjd /* 1854185029Spjd * zfs_get_zplprop() will either find a value or give us 1855185029Spjd * the default value (if there is one). 1856185029Spjd */ 1857185029Spjd if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1858185029Spjd return (error); 1859185029Spjd VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1860185029Spjd return (0); 1861185029Spjd} 1862185029Spjd 1863185029Spjd/* 1864185029Spjd * inputs: 1865185029Spjd * zc_name name of filesystem 1866185029Spjd * zc_nvlist_dst_size size of buffer for zpl property nvlist 1867185029Spjd * 1868185029Spjd * outputs: 1869185029Spjd * zc_nvlist_dst zpl property nvlist 1870185029Spjd * zc_nvlist_dst_size size of zpl property nvlist 1871185029Spjd */ 1872185029Spjdstatic int 1873185029Spjdzfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1874185029Spjd{ 1875185029Spjd objset_t *os; 1876185029Spjd int err; 1877185029Spjd 1878219089Spjd /* XXX reading without owning */ 1879219089Spjd if (err = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1880185029Spjd return (err); 1881185029Spjd 1882185029Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1883185029Spjd 1884185029Spjd /* 1885185029Spjd * NB: nvl_add_zplprop() will read the objset contents, 1886185029Spjd * which we aren't supposed to do with a DS_MODE_USER 1887185029Spjd * hold, because it could be inconsistent. 1888185029Spjd */ 1889185029Spjd if (zc->zc_nvlist_dst != 0 && 1890185029Spjd !zc->zc_objset_stats.dds_inconsistent && 1891185029Spjd dmu_objset_type(os) == DMU_OST_ZFS) { 1892185029Spjd nvlist_t *nv; 1893185029Spjd 1894185029Spjd VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1895185029Spjd if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1896185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1897185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1898185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1899185029Spjd err = put_nvlist(zc, nv); 1900185029Spjd nvlist_free(nv); 1901185029Spjd } else { 1902185029Spjd err = ENOENT; 1903185029Spjd } 1904219089Spjd dmu_objset_rele(os, FTAG); 1905185029Spjd return (err); 1906185029Spjd} 1907185029Spjd 1908219089Spjdboolean_t 1909209962Smmdataset_name_hidden(const char *name) 1910209962Smm{ 1911209962Smm /* 1912209962Smm * Skip over datasets that are not visible in this zone, 1913209962Smm * internal datasets (which have a $ in their name), and 1914209962Smm * temporary datasets (which have a % in their name). 1915209962Smm */ 1916209962Smm if (strchr(name, '$') != NULL) 1917209962Smm return (B_TRUE); 1918209962Smm if (strchr(name, '%') != NULL) 1919209962Smm return (B_TRUE); 1920209962Smm if (!INGLOBALZONE(curthread) && !zone_dataset_visible(name, NULL)) 1921209962Smm return (B_TRUE); 1922209962Smm return (B_FALSE); 1923209962Smm} 1924209962Smm 1925185029Spjd/* 1926185029Spjd * inputs: 1927185029Spjd * zc_name name of filesystem 1928185029Spjd * zc_cookie zap cursor 1929185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1930185029Spjd * 1931185029Spjd * outputs: 1932185029Spjd * zc_name name of next filesystem 1933209962Smm * zc_cookie zap cursor 1934185029Spjd * zc_objset_stats stats 1935185029Spjd * zc_nvlist_dst property nvlist 1936185029Spjd * zc_nvlist_dst_size size of property nvlist 1937185029Spjd */ 1938185029Spjdstatic int 1939168404Spjdzfs_ioc_dataset_list_next(zfs_cmd_t *zc) 1940168404Spjd{ 1941168404Spjd objset_t *os; 1942168404Spjd int error; 1943168404Spjd char *p; 1944219089Spjd size_t orig_len = strlen(zc->zc_name); 1945168404Spjd 1946219089Spjdtop: 1947219089Spjd if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) { 1948168404Spjd if (error == ENOENT) 1949168404Spjd error = ESRCH; 1950168404Spjd return (error); 1951168404Spjd } 1952168404Spjd 1953168404Spjd p = strrchr(zc->zc_name, '/'); 1954168404Spjd if (p == NULL || p[1] != '\0') 1955168404Spjd (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 1956168404Spjd p = zc->zc_name + strlen(zc->zc_name); 1957168404Spjd 1958209962Smm /* 1959209962Smm * Pre-fetch the datasets. dmu_objset_prefetch() always returns 0 1960209962Smm * but is not declared void because its called by dmu_objset_find(). 1961209962Smm */ 1962207626Smm if (zc->zc_cookie == 0) { 1963207626Smm uint64_t cookie = 0; 1964207626Smm int len = sizeof (zc->zc_name) - (p - zc->zc_name); 1965207626Smm 1966207626Smm while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) 1967224814Smm if (dataset_name_hidden(zc->zc_name) == B_FALSE) 1968224814Smm (void) dmu_objset_prefetch(zc->zc_name, NULL); 1969207626Smm } 1970207626Smm 1971168404Spjd do { 1972168404Spjd error = dmu_dir_list_next(os, 1973168404Spjd sizeof (zc->zc_name) - (p - zc->zc_name), p, 1974168404Spjd NULL, &zc->zc_cookie); 1975168404Spjd if (error == ENOENT) 1976168404Spjd error = ESRCH; 1977219089Spjd } while (error == 0 && dataset_name_hidden(zc->zc_name) && 1978219089Spjd !(zc->zc_iflags & FKIOCTL)); 1979219089Spjd dmu_objset_rele(os, FTAG); 1980168404Spjd 1981219089Spjd /* 1982219089Spjd * If it's an internal dataset (ie. with a '$' in its name), 1983219089Spjd * don't try to get stats for it, otherwise we'll return ENOENT. 1984219089Spjd */ 1985219089Spjd if (error == 0 && strchr(zc->zc_name, '$') == NULL) { 1986168404Spjd error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 1987219089Spjd if (error == ENOENT) { 1988219089Spjd /* We lost a race with destroy, get the next one. */ 1989219089Spjd zc->zc_name[orig_len] = '\0'; 1990219089Spjd goto top; 1991219089Spjd } 1992219089Spjd } 1993168404Spjd return (error); 1994168404Spjd} 1995168404Spjd 1996185029Spjd/* 1997185029Spjd * inputs: 1998185029Spjd * zc_name name of filesystem 1999185029Spjd * zc_cookie zap cursor 2000185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 2001185029Spjd * 2002185029Spjd * outputs: 2003185029Spjd * zc_name name of next snapshot 2004185029Spjd * zc_objset_stats stats 2005185029Spjd * zc_nvlist_dst property nvlist 2006185029Spjd * zc_nvlist_dst_size size of property nvlist 2007185029Spjd */ 2008168404Spjdstatic int 2009168404Spjdzfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 2010168404Spjd{ 2011168404Spjd objset_t *os; 2012168404Spjd int error; 2013168404Spjd 2014219089Spjdtop: 2015219089Spjd if (zc->zc_cookie == 0) 2016219089Spjd (void) dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 2017219089Spjd NULL, DS_FIND_SNAPSHOTS); 2018219089Spjd 2019219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &os); 2020185029Spjd if (error) 2021185029Spjd return (error == ENOENT ? ESRCH : error); 2022168404Spjd 2023168404Spjd /* 2024168404Spjd * A dataset name of maximum length cannot have any snapshots, 2025168404Spjd * so exit immediately. 2026168404Spjd */ 2027168404Spjd if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 2028219089Spjd dmu_objset_rele(os, FTAG); 2029168404Spjd return (ESRCH); 2030168404Spjd } 2031168404Spjd 2032168404Spjd error = dmu_snapshot_list_next(os, 2033168404Spjd sizeof (zc->zc_name) - strlen(zc->zc_name), 2034219089Spjd zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie, 2035219089Spjd NULL); 2036219089Spjd 2037219089Spjd if (error == 0) { 2038219089Spjd dsl_dataset_t *ds; 2039219089Spjd dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool; 2040219089Spjd 2041219089Spjd /* 2042219089Spjd * Since we probably don't have a hold on this snapshot, 2043219089Spjd * it's possible that the objsetid could have been destroyed 2044219089Spjd * and reused for a new objset. It's OK if this happens during 2045219089Spjd * a zfs send operation, since the new createtxg will be 2046219089Spjd * beyond the range we're interested in. 2047219089Spjd */ 2048219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 2049219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds); 2050219089Spjd rw_exit(&dp->dp_config_rwlock); 2051219089Spjd if (error) { 2052219089Spjd if (error == ENOENT) { 2053219089Spjd /* Racing with destroy, get the next one. */ 2054219089Spjd *strchr(zc->zc_name, '@') = '\0'; 2055219089Spjd dmu_objset_rele(os, FTAG); 2056219089Spjd goto top; 2057219089Spjd } 2058219089Spjd } else { 2059219089Spjd objset_t *ossnap; 2060219089Spjd 2061219089Spjd error = dmu_objset_from_ds(ds, &ossnap); 2062219089Spjd if (error == 0) 2063219089Spjd error = zfs_ioc_objset_stats_impl(zc, ossnap); 2064219089Spjd dsl_dataset_rele(ds, FTAG); 2065219089Spjd } 2066219089Spjd } else if (error == ENOENT) { 2067185029Spjd error = ESRCH; 2068219089Spjd } 2069168404Spjd 2070219089Spjd dmu_objset_rele(os, FTAG); 2071185029Spjd /* if we failed, undo the @ that we tacked on to zc_name */ 2072185029Spjd if (error) 2073185029Spjd *strchr(zc->zc_name, '@') = '\0'; 2074168404Spjd return (error); 2075168404Spjd} 2076168404Spjd 2077219089Spjdstatic int 2078219089Spjdzfs_prop_set_userquota(const char *dsname, nvpair_t *pair) 2079168404Spjd{ 2080219089Spjd const char *propname = nvpair_name(pair); 2081219089Spjd uint64_t *valary; 2082219089Spjd unsigned int vallen; 2083219089Spjd const char *domain; 2084219089Spjd char *dash; 2085219089Spjd zfs_userquota_prop_t type; 2086219089Spjd uint64_t rid; 2087219089Spjd uint64_t quota; 2088219089Spjd zfsvfs_t *zfsvfs; 2089219089Spjd int err; 2090168404Spjd 2091219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2092219089Spjd nvlist_t *attrs; 2093219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2094219089Spjd if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2095219089Spjd &pair) != 0) 2096219089Spjd return (EINVAL); 2097219089Spjd } 2098219089Spjd 2099185029Spjd /* 2100219089Spjd * A correctly constructed propname is encoded as 2101219089Spjd * userquota@<rid>-<domain>. 2102185029Spjd */ 2103219089Spjd if ((dash = strchr(propname, '-')) == NULL || 2104219089Spjd nvpair_value_uint64_array(pair, &valary, &vallen) != 0 || 2105219089Spjd vallen != 3) 2106219089Spjd return (EINVAL); 2107168404Spjd 2108219089Spjd domain = dash + 1; 2109219089Spjd type = valary[0]; 2110219089Spjd rid = valary[1]; 2111219089Spjd quota = valary[2]; 2112168404Spjd 2113219089Spjd err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_FALSE); 2114219089Spjd if (err == 0) { 2115219089Spjd err = zfs_set_userquota(zfsvfs, type, domain, rid, quota); 2116219089Spjd zfsvfs_rele(zfsvfs, FTAG); 2117219089Spjd } 2118209962Smm 2119219089Spjd return (err); 2120219089Spjd} 2121168404Spjd 2122219089Spjd/* 2123219089Spjd * If the named property is one that has a special function to set its value, 2124219089Spjd * return 0 on success and a positive error code on failure; otherwise if it is 2125219089Spjd * not one of the special properties handled by this function, return -1. 2126219089Spjd * 2127219089Spjd * XXX: It would be better for callers of the property interface if we handled 2128219089Spjd * these special cases in dsl_prop.c (in the dsl layer). 2129219089Spjd */ 2130219089Spjdstatic int 2131219089Spjdzfs_prop_set_special(const char *dsname, zprop_source_t source, 2132219089Spjd nvpair_t *pair) 2133219089Spjd{ 2134219089Spjd const char *propname = nvpair_name(pair); 2135219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 2136219089Spjd uint64_t intval; 2137219089Spjd int err; 2138209962Smm 2139219089Spjd if (prop == ZPROP_INVAL) { 2140219089Spjd if (zfs_prop_userquota(propname)) 2141219089Spjd return (zfs_prop_set_userquota(dsname, pair)); 2142219089Spjd return (-1); 2143219089Spjd } 2144185029Spjd 2145219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2146219089Spjd nvlist_t *attrs; 2147219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2148219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2149219089Spjd &pair) == 0); 2150219089Spjd } 2151168404Spjd 2152219089Spjd if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) 2153219089Spjd return (-1); 2154185029Spjd 2155219089Spjd VERIFY(0 == nvpair_value_uint64(pair, &intval)); 2156185029Spjd 2157219089Spjd switch (prop) { 2158219089Spjd case ZFS_PROP_QUOTA: 2159219089Spjd err = dsl_dir_set_quota(dsname, source, intval); 2160219089Spjd break; 2161219089Spjd case ZFS_PROP_REFQUOTA: 2162219089Spjd err = dsl_dataset_set_quota(dsname, source, intval); 2163219089Spjd break; 2164219089Spjd case ZFS_PROP_RESERVATION: 2165219089Spjd err = dsl_dir_set_reservation(dsname, source, intval); 2166219089Spjd break; 2167219089Spjd case ZFS_PROP_REFRESERVATION: 2168219089Spjd err = dsl_dataset_set_reservation(dsname, source, intval); 2169219089Spjd break; 2170219089Spjd case ZFS_PROP_VOLSIZE: 2171219089Spjd err = zvol_set_volsize(dsname, ddi_driver_major(zfs_dip), 2172219089Spjd intval); 2173219089Spjd break; 2174219089Spjd case ZFS_PROP_VERSION: 2175219089Spjd { 2176219089Spjd zfsvfs_t *zfsvfs; 2177219089Spjd 2178219089Spjd if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) 2179185029Spjd break; 2180201143Sdelphij 2181219089Spjd err = zfs_set_version(zfsvfs, intval); 2182219089Spjd zfsvfs_rele(zfsvfs, FTAG); 2183168404Spjd 2184219089Spjd if (err == 0 && intval >= ZPL_VERSION_USERSPACE) { 2185219089Spjd zfs_cmd_t *zc; 2186185029Spjd 2187219089Spjd zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2188219089Spjd (void) strcpy(zc->zc_name, dsname); 2189219089Spjd (void) zfs_ioc_userspace_upgrade(zc); 2190219089Spjd kmem_free(zc, sizeof (zfs_cmd_t)); 2191185029Spjd } 2192219089Spjd break; 2193219089Spjd } 2194185029Spjd 2195219089Spjd default: 2196219089Spjd err = -1; 2197219089Spjd } 2198168404Spjd 2199219089Spjd return (err); 2200219089Spjd} 2201185029Spjd 2202219089Spjd/* 2203219089Spjd * This function is best effort. If it fails to set any of the given properties, 2204219089Spjd * it continues to set as many as it can and returns the first error 2205219089Spjd * encountered. If the caller provides a non-NULL errlist, it also gives the 2206219089Spjd * complete list of names of all the properties it failed to set along with the 2207219089Spjd * corresponding error numbers. The caller is responsible for freeing the 2208219089Spjd * returned errlist. 2209219089Spjd * 2210219089Spjd * If every property is set successfully, zero is returned and the list pointed 2211219089Spjd * at by errlist is NULL. 2212219089Spjd */ 2213219089Spjdint 2214219089Spjdzfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, 2215219089Spjd nvlist_t **errlist) 2216219089Spjd{ 2217219089Spjd nvpair_t *pair; 2218219089Spjd nvpair_t *propval; 2219219089Spjd int rv = 0; 2220219089Spjd uint64_t intval; 2221219089Spjd char *strval; 2222219089Spjd nvlist_t *genericnvl; 2223219089Spjd nvlist_t *errors; 2224219089Spjd nvlist_t *retrynvl; 2225168404Spjd 2226219089Spjd VERIFY(nvlist_alloc(&genericnvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2227219089Spjd VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2228219089Spjd VERIFY(nvlist_alloc(&retrynvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2229168404Spjd 2230219089Spjdretry: 2231219089Spjd pair = NULL; 2232219089Spjd while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 2233219089Spjd const char *propname = nvpair_name(pair); 2234219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 2235219089Spjd int err = 0; 2236185029Spjd 2237219089Spjd /* decode the property value */ 2238219089Spjd propval = pair; 2239219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2240219089Spjd nvlist_t *attrs; 2241219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2242219089Spjd if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2243219089Spjd &propval) != 0) 2244219089Spjd err = EINVAL; 2245219089Spjd } 2246168404Spjd 2247219089Spjd /* Validate value type */ 2248219089Spjd if (err == 0 && prop == ZPROP_INVAL) { 2249219089Spjd if (zfs_prop_user(propname)) { 2250219089Spjd if (nvpair_type(propval) != DATA_TYPE_STRING) 2251219089Spjd err = EINVAL; 2252219089Spjd } else if (zfs_prop_userquota(propname)) { 2253219089Spjd if (nvpair_type(propval) != 2254219089Spjd DATA_TYPE_UINT64_ARRAY) 2255219089Spjd err = EINVAL; 2256209962Smm } 2257219089Spjd } else if (err == 0) { 2258219089Spjd if (nvpair_type(propval) == DATA_TYPE_STRING) { 2259219089Spjd if (zfs_prop_get_type(prop) != PROP_TYPE_STRING) 2260219089Spjd err = EINVAL; 2261219089Spjd } else if (nvpair_type(propval) == DATA_TYPE_UINT64) { 2262168404Spjd const char *unused; 2263168404Spjd 2264219089Spjd VERIFY(nvpair_value_uint64(propval, 2265219089Spjd &intval) == 0); 2266168404Spjd 2267168404Spjd switch (zfs_prop_get_type(prop)) { 2268185029Spjd case PROP_TYPE_NUMBER: 2269168404Spjd break; 2270185029Spjd case PROP_TYPE_STRING: 2271219089Spjd err = EINVAL; 2272219089Spjd break; 2273185029Spjd case PROP_TYPE_INDEX: 2274168404Spjd if (zfs_prop_index_to_string(prop, 2275219089Spjd intval, &unused) != 0) 2276219089Spjd err = EINVAL; 2277168404Spjd break; 2278168404Spjd default: 2279185029Spjd cmn_err(CE_PANIC, 2280185029Spjd "unknown property type"); 2281168404Spjd } 2282168404Spjd } else { 2283219089Spjd err = EINVAL; 2284168404Spjd } 2285168404Spjd } 2286219089Spjd 2287219089Spjd /* Validate permissions */ 2288219089Spjd if (err == 0) 2289219089Spjd err = zfs_check_settable(dsname, pair, CRED()); 2290219089Spjd 2291219089Spjd if (err == 0) { 2292219089Spjd err = zfs_prop_set_special(dsname, source, pair); 2293219089Spjd if (err == -1) { 2294219089Spjd /* 2295219089Spjd * For better performance we build up a list of 2296219089Spjd * properties to set in a single transaction. 2297219089Spjd */ 2298219089Spjd err = nvlist_add_nvpair(genericnvl, pair); 2299219089Spjd } else if (err != 0 && nvl != retrynvl) { 2300219089Spjd /* 2301219089Spjd * This may be a spurious error caused by 2302219089Spjd * receiving quota and reservation out of order. 2303219089Spjd * Try again in a second pass. 2304219089Spjd */ 2305219089Spjd err = nvlist_add_nvpair(retrynvl, pair); 2306219089Spjd } 2307219089Spjd } 2308219089Spjd 2309219089Spjd if (err != 0) 2310219089Spjd VERIFY(nvlist_add_int32(errors, propname, err) == 0); 2311168404Spjd } 2312168404Spjd 2313219089Spjd if (nvl != retrynvl && !nvlist_empty(retrynvl)) { 2314219089Spjd nvl = retrynvl; 2315219089Spjd goto retry; 2316209962Smm } 2317219089Spjd 2318219089Spjd if (!nvlist_empty(genericnvl) && 2319219089Spjd dsl_props_set(dsname, source, genericnvl) != 0) { 2320219089Spjd /* 2321219089Spjd * If this fails, we still want to set as many properties as we 2322219089Spjd * can, so try setting them individually. 2323219089Spjd */ 2324219089Spjd pair = NULL; 2325219089Spjd while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) { 2326219089Spjd const char *propname = nvpair_name(pair); 2327219089Spjd int err = 0; 2328219089Spjd 2329219089Spjd propval = pair; 2330219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2331219089Spjd nvlist_t *attrs; 2332219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2333219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2334219089Spjd &propval) == 0); 2335219089Spjd } 2336219089Spjd 2337219089Spjd if (nvpair_type(propval) == DATA_TYPE_STRING) { 2338219089Spjd VERIFY(nvpair_value_string(propval, 2339219089Spjd &strval) == 0); 2340219089Spjd err = dsl_prop_set(dsname, propname, source, 1, 2341219089Spjd strlen(strval) + 1, strval); 2342219089Spjd } else { 2343219089Spjd VERIFY(nvpair_value_uint64(propval, 2344219089Spjd &intval) == 0); 2345219089Spjd err = dsl_prop_set(dsname, propname, source, 8, 2346219089Spjd 1, &intval); 2347219089Spjd } 2348219089Spjd 2349219089Spjd if (err != 0) { 2350219089Spjd VERIFY(nvlist_add_int32(errors, propname, 2351219089Spjd err) == 0); 2352219089Spjd } 2353219089Spjd } 2354219089Spjd } 2355209962Smm nvlist_free(genericnvl); 2356219089Spjd nvlist_free(retrynvl); 2357219089Spjd 2358219089Spjd if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) { 2359219089Spjd nvlist_free(errors); 2360219089Spjd errors = NULL; 2361219089Spjd } else { 2362219089Spjd VERIFY(nvpair_value_int32(pair, &rv) == 0); 2363219089Spjd } 2364219089Spjd 2365219089Spjd if (errlist == NULL) 2366219089Spjd nvlist_free(errors); 2367219089Spjd else 2368219089Spjd *errlist = errors; 2369219089Spjd 2370219089Spjd return (rv); 2371209962Smm} 2372209962Smm 2373209962Smm/* 2374209962Smm * Check that all the properties are valid user properties. 2375209962Smm */ 2376209962Smmstatic int 2377209962Smmzfs_check_userprops(char *fsname, nvlist_t *nvl) 2378209962Smm{ 2379219089Spjd nvpair_t *pair = NULL; 2380209962Smm int error = 0; 2381209962Smm 2382219089Spjd while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 2383219089Spjd const char *propname = nvpair_name(pair); 2384209962Smm char *valstr; 2385209962Smm 2386209962Smm if (!zfs_prop_user(propname) || 2387219089Spjd nvpair_type(pair) != DATA_TYPE_STRING) 2388209962Smm return (EINVAL); 2389209962Smm 2390209962Smm if (error = zfs_secpolicy_write_perms(fsname, 2391209962Smm ZFS_DELEG_PERM_USERPROP, CRED())) 2392209962Smm return (error); 2393209962Smm 2394209962Smm if (strlen(propname) >= ZAP_MAXNAMELEN) 2395209962Smm return (ENAMETOOLONG); 2396209962Smm 2397219089Spjd VERIFY(nvpair_value_string(pair, &valstr) == 0); 2398209962Smm if (strlen(valstr) >= ZAP_MAXVALUELEN) 2399209962Smm return (E2BIG); 2400209962Smm } 2401168404Spjd return (0); 2402168404Spjd} 2403168404Spjd 2404219089Spjdstatic void 2405219089Spjdprops_skip(nvlist_t *props, nvlist_t *skipped, nvlist_t **newprops) 2406219089Spjd{ 2407219089Spjd nvpair_t *pair; 2408219089Spjd 2409219089Spjd VERIFY(nvlist_alloc(newprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2410219089Spjd 2411219089Spjd pair = NULL; 2412219089Spjd while ((pair = nvlist_next_nvpair(props, pair)) != NULL) { 2413219089Spjd if (nvlist_exists(skipped, nvpair_name(pair))) 2414219089Spjd continue; 2415219089Spjd 2416219089Spjd VERIFY(nvlist_add_nvpair(*newprops, pair) == 0); 2417219089Spjd } 2418219089Spjd} 2419219089Spjd 2420219089Spjdstatic int 2421219089Spjdclear_received_props(objset_t *os, const char *fs, nvlist_t *props, 2422219089Spjd nvlist_t *skipped) 2423219089Spjd{ 2424219089Spjd int err = 0; 2425219089Spjd nvlist_t *cleared_props = NULL; 2426219089Spjd props_skip(props, skipped, &cleared_props); 2427219089Spjd if (!nvlist_empty(cleared_props)) { 2428219089Spjd /* 2429219089Spjd * Acts on local properties until the dataset has received 2430219089Spjd * properties at least once on or after SPA_VERSION_RECVD_PROPS. 2431219089Spjd */ 2432219089Spjd zprop_source_t flags = (ZPROP_SRC_NONE | 2433219089Spjd (dsl_prop_get_hasrecvd(os) ? ZPROP_SRC_RECEIVED : 0)); 2434219089Spjd err = zfs_set_prop_nvlist(fs, flags, cleared_props, NULL); 2435219089Spjd } 2436219089Spjd nvlist_free(cleared_props); 2437219089Spjd return (err); 2438219089Spjd} 2439219089Spjd 2440185029Spjd/* 2441185029Spjd * inputs: 2442185029Spjd * zc_name name of filesystem 2443209962Smm * zc_value name of property to set 2444185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 2445219089Spjd * zc_cookie received properties flag 2446185029Spjd * 2447219089Spjd * outputs: 2448219089Spjd * zc_nvlist_dst{_size} error for each unapplied received property 2449185029Spjd */ 2450168404Spjdstatic int 2451168404Spjdzfs_ioc_set_prop(zfs_cmd_t *zc) 2452168404Spjd{ 2453168404Spjd nvlist_t *nvl; 2454219089Spjd boolean_t received = zc->zc_cookie; 2455219089Spjd zprop_source_t source = (received ? ZPROP_SRC_RECEIVED : 2456219089Spjd ZPROP_SRC_LOCAL); 2457219089Spjd nvlist_t *errors = NULL; 2458168404Spjd int error; 2459168404Spjd 2460185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2461219089Spjd zc->zc_iflags, &nvl)) != 0) 2462185029Spjd return (error); 2463168404Spjd 2464219089Spjd if (received) { 2465185029Spjd nvlist_t *origprops; 2466185029Spjd objset_t *os; 2467185029Spjd 2468219089Spjd if (dmu_objset_hold(zc->zc_name, FTAG, &os) == 0) { 2469219089Spjd if (dsl_prop_get_received(os, &origprops) == 0) { 2470219089Spjd (void) clear_received_props(os, 2471219089Spjd zc->zc_name, origprops, nvl); 2472185029Spjd nvlist_free(origprops); 2473185029Spjd } 2474219089Spjd 2475219089Spjd dsl_prop_set_hasrecvd(os); 2476219089Spjd dmu_objset_rele(os, FTAG); 2477185029Spjd } 2478219089Spjd } 2479185029Spjd 2480219089Spjd error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, &errors); 2481219089Spjd 2482219089Spjd if (zc->zc_nvlist_dst != 0 && errors != NULL) { 2483219089Spjd (void) put_nvlist(zc, errors); 2484168404Spjd } 2485168404Spjd 2486219089Spjd nvlist_free(errors); 2487168404Spjd nvlist_free(nvl); 2488168404Spjd return (error); 2489168404Spjd} 2490168404Spjd 2491185029Spjd/* 2492185029Spjd * inputs: 2493185029Spjd * zc_name name of filesystem 2494185029Spjd * zc_value name of property to inherit 2495219089Spjd * zc_cookie revert to received value if TRUE 2496185029Spjd * 2497185029Spjd * outputs: none 2498185029Spjd */ 2499168404Spjdstatic int 2500185029Spjdzfs_ioc_inherit_prop(zfs_cmd_t *zc) 2501185029Spjd{ 2502219089Spjd const char *propname = zc->zc_value; 2503219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 2504219089Spjd boolean_t received = zc->zc_cookie; 2505219089Spjd zprop_source_t source = (received 2506219089Spjd ? ZPROP_SRC_NONE /* revert to received value, if any */ 2507219089Spjd : ZPROP_SRC_INHERITED); /* explicitly inherit */ 2508219089Spjd 2509219089Spjd if (received) { 2510219089Spjd nvlist_t *dummy; 2511219089Spjd nvpair_t *pair; 2512219089Spjd zprop_type_t type; 2513219089Spjd int err; 2514219089Spjd 2515219089Spjd /* 2516219089Spjd * zfs_prop_set_special() expects properties in the form of an 2517219089Spjd * nvpair with type info. 2518219089Spjd */ 2519219089Spjd if (prop == ZPROP_INVAL) { 2520219089Spjd if (!zfs_prop_user(propname)) 2521219089Spjd return (EINVAL); 2522219089Spjd 2523219089Spjd type = PROP_TYPE_STRING; 2524219089Spjd } else if (prop == ZFS_PROP_VOLSIZE || 2525219089Spjd prop == ZFS_PROP_VERSION) { 2526219089Spjd return (EINVAL); 2527219089Spjd } else { 2528219089Spjd type = zfs_prop_get_type(prop); 2529219089Spjd } 2530219089Spjd 2531219089Spjd VERIFY(nvlist_alloc(&dummy, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2532219089Spjd 2533219089Spjd switch (type) { 2534219089Spjd case PROP_TYPE_STRING: 2535219089Spjd VERIFY(0 == nvlist_add_string(dummy, propname, "")); 2536219089Spjd break; 2537219089Spjd case PROP_TYPE_NUMBER: 2538219089Spjd case PROP_TYPE_INDEX: 2539219089Spjd VERIFY(0 == nvlist_add_uint64(dummy, propname, 0)); 2540219089Spjd break; 2541219089Spjd default: 2542219089Spjd nvlist_free(dummy); 2543219089Spjd return (EINVAL); 2544219089Spjd } 2545219089Spjd 2546219089Spjd pair = nvlist_next_nvpair(dummy, NULL); 2547219089Spjd err = zfs_prop_set_special(zc->zc_name, source, pair); 2548219089Spjd nvlist_free(dummy); 2549219089Spjd if (err != -1) 2550219089Spjd return (err); /* special property already handled */ 2551219089Spjd } else { 2552219089Spjd /* 2553219089Spjd * Only check this in the non-received case. We want to allow 2554219089Spjd * 'inherit -S' to revert non-inheritable properties like quota 2555219089Spjd * and reservation to the received or default values even though 2556219089Spjd * they are not considered inheritable. 2557219089Spjd */ 2558219089Spjd if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 2559219089Spjd return (EINVAL); 2560219089Spjd } 2561219089Spjd 2562185029Spjd /* the property name has been validated by zfs_secpolicy_inherit() */ 2563219089Spjd return (dsl_prop_set(zc->zc_name, zc->zc_value, source, 0, 0, NULL)); 2564185029Spjd} 2565185029Spjd 2566185029Spjdstatic int 2567169055Spjdzfs_ioc_pool_set_props(zfs_cmd_t *zc) 2568168404Spjd{ 2569185029Spjd nvlist_t *props; 2570168404Spjd spa_t *spa; 2571185029Spjd int error; 2572219089Spjd nvpair_t *pair; 2573168404Spjd 2574219089Spjd if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2575219089Spjd zc->zc_iflags, &props)) 2576168404Spjd return (error); 2577168404Spjd 2578209962Smm /* 2579209962Smm * If the only property is the configfile, then just do a spa_lookup() 2580209962Smm * to handle the faulted case. 2581209962Smm */ 2582219089Spjd pair = nvlist_next_nvpair(props, NULL); 2583219089Spjd if (pair != NULL && strcmp(nvpair_name(pair), 2584209962Smm zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 2585219089Spjd nvlist_next_nvpair(props, pair) == NULL) { 2586209962Smm mutex_enter(&spa_namespace_lock); 2587209962Smm if ((spa = spa_lookup(zc->zc_name)) != NULL) { 2588209962Smm spa_configfile_set(spa, props, B_FALSE); 2589209962Smm spa_config_sync(spa, B_FALSE, B_TRUE); 2590209962Smm } 2591209962Smm mutex_exit(&spa_namespace_lock); 2592219089Spjd if (spa != NULL) { 2593219089Spjd nvlist_free(props); 2594209962Smm return (0); 2595219089Spjd } 2596209962Smm } 2597209962Smm 2598168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2599185029Spjd nvlist_free(props); 2600168404Spjd return (error); 2601168404Spjd } 2602168404Spjd 2603185029Spjd error = spa_prop_set(spa, props); 2604168404Spjd 2605185029Spjd nvlist_free(props); 2606168404Spjd spa_close(spa, FTAG); 2607168404Spjd 2608168404Spjd return (error); 2609168404Spjd} 2610168404Spjd 2611168404Spjdstatic int 2612169055Spjdzfs_ioc_pool_get_props(zfs_cmd_t *zc) 2613168404Spjd{ 2614168404Spjd spa_t *spa; 2615168404Spjd int error; 2616168404Spjd nvlist_t *nvp = NULL; 2617168404Spjd 2618209962Smm if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2619209962Smm /* 2620209962Smm * If the pool is faulted, there may be properties we can still 2621209962Smm * get (such as altroot and cachefile), so attempt to get them 2622209962Smm * anyway. 2623209962Smm */ 2624209962Smm mutex_enter(&spa_namespace_lock); 2625209962Smm if ((spa = spa_lookup(zc->zc_name)) != NULL) 2626209962Smm error = spa_prop_get(spa, &nvp); 2627209962Smm mutex_exit(&spa_namespace_lock); 2628209962Smm } else { 2629209962Smm error = spa_prop_get(spa, &nvp); 2630209962Smm spa_close(spa, FTAG); 2631209962Smm } 2632168404Spjd 2633168404Spjd if (error == 0 && zc->zc_nvlist_dst != 0) 2634168404Spjd error = put_nvlist(zc, nvp); 2635168404Spjd else 2636168404Spjd error = EFAULT; 2637168404Spjd 2638209962Smm nvlist_free(nvp); 2639168404Spjd return (error); 2640168404Spjd} 2641168404Spjd 2642185029Spjd/* 2643185029Spjd * inputs: 2644185029Spjd * zc_name name of filesystem 2645185029Spjd * zc_nvlist_src{_size} nvlist of delegated permissions 2646185029Spjd * zc_perm_action allow/unallow flag 2647185029Spjd * 2648185029Spjd * outputs: none 2649185029Spjd */ 2650185029Spjdstatic int 2651185029Spjdzfs_ioc_set_fsacl(zfs_cmd_t *zc) 2652185029Spjd{ 2653185029Spjd int error; 2654185029Spjd nvlist_t *fsaclnv = NULL; 2655185029Spjd 2656185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2657219089Spjd zc->zc_iflags, &fsaclnv)) != 0) 2658185029Spjd return (error); 2659185029Spjd 2660185029Spjd /* 2661185029Spjd * Verify nvlist is constructed correctly 2662185029Spjd */ 2663185029Spjd if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 2664185029Spjd nvlist_free(fsaclnv); 2665185029Spjd return (EINVAL); 2666185029Spjd } 2667185029Spjd 2668185029Spjd /* 2669185029Spjd * If we don't have PRIV_SYS_MOUNT, then validate 2670185029Spjd * that user is allowed to hand out each permission in 2671185029Spjd * the nvlist(s) 2672185029Spjd */ 2673185029Spjd 2674185029Spjd error = secpolicy_zfs(CRED()); 2675185029Spjd if (error) { 2676185029Spjd if (zc->zc_perm_action == B_FALSE) { 2677185029Spjd error = dsl_deleg_can_allow(zc->zc_name, 2678185029Spjd fsaclnv, CRED()); 2679185029Spjd } else { 2680185029Spjd error = dsl_deleg_can_unallow(zc->zc_name, 2681185029Spjd fsaclnv, CRED()); 2682185029Spjd } 2683185029Spjd } 2684185029Spjd 2685185029Spjd if (error == 0) 2686185029Spjd error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 2687185029Spjd 2688185029Spjd nvlist_free(fsaclnv); 2689185029Spjd return (error); 2690185029Spjd} 2691185029Spjd 2692185029Spjd/* 2693185029Spjd * inputs: 2694185029Spjd * zc_name name of filesystem 2695185029Spjd * 2696185029Spjd * outputs: 2697185029Spjd * zc_nvlist_src{_size} nvlist of delegated permissions 2698185029Spjd */ 2699185029Spjdstatic int 2700185029Spjdzfs_ioc_get_fsacl(zfs_cmd_t *zc) 2701185029Spjd{ 2702185029Spjd nvlist_t *nvp; 2703185029Spjd int error; 2704185029Spjd 2705185029Spjd if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 2706185029Spjd error = put_nvlist(zc, nvp); 2707185029Spjd nvlist_free(nvp); 2708185029Spjd } 2709185029Spjd 2710185029Spjd return (error); 2711185029Spjd} 2712185029Spjd 2713185029Spjd/* 2714168404Spjd * Search the vfs list for a specified resource. Returns a pointer to it 2715168404Spjd * or NULL if no suitable entry is found. The caller of this routine 2716168404Spjd * is responsible for releasing the returned vfs pointer. 2717168404Spjd */ 2718168404Spjdstatic vfs_t * 2719168404Spjdzfs_get_vfs(const char *resource) 2720168404Spjd{ 2721168404Spjd vfs_t *vfsp; 2722168404Spjd 2723168404Spjd mtx_lock(&mountlist_mtx); 2724168404Spjd TAILQ_FOREACH(vfsp, &mountlist, mnt_list) { 2725185029Spjd if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 2726168404Spjd VFS_HOLD(vfsp); 2727168404Spjd break; 2728168404Spjd } 2729168404Spjd } 2730168404Spjd mtx_unlock(&mountlist_mtx); 2731168404Spjd return (vfsp); 2732168404Spjd} 2733168404Spjd 2734185029Spjd/* ARGSUSED */ 2735168404Spjdstatic void 2736185029Spjdzfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 2737168404Spjd{ 2738185029Spjd zfs_creat_t *zct = arg; 2739168404Spjd 2740185029Spjd zfs_create_fs(os, cr, zct->zct_zplprops, tx); 2741168404Spjd} 2742168404Spjd 2743185029Spjd#define ZFS_PROP_UNDEFINED ((uint64_t)-1) 2744185029Spjd 2745185029Spjd/* 2746185029Spjd * inputs: 2747185029Spjd * createprops list of properties requested by creator 2748185029Spjd * default_zplver zpl version to use if unspecified in createprops 2749185029Spjd * fuids_ok fuids allowed in this version of the spa? 2750185029Spjd * os parent objset pointer (NULL if root fs) 2751185029Spjd * 2752185029Spjd * outputs: 2753185029Spjd * zplprops values for the zplprops we attach to the master node object 2754185029Spjd * is_ci true if requested file system will be purely case-insensitive 2755185029Spjd * 2756185029Spjd * Determine the settings for utf8only, normalization and 2757185029Spjd * casesensitivity. Specific values may have been requested by the 2758185029Spjd * creator and/or we can inherit values from the parent dataset. If 2759185029Spjd * the file system is of too early a vintage, a creator can not 2760185029Spjd * request settings for these properties, even if the requested 2761185029Spjd * setting is the default value. We don't actually want to create dsl 2762185029Spjd * properties for these, so remove them from the source nvlist after 2763185029Spjd * processing. 2764185029Spjd */ 2765168404Spjdstatic int 2766209962Smmzfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 2767219089Spjd boolean_t fuids_ok, boolean_t sa_ok, nvlist_t *createprops, 2768219089Spjd nvlist_t *zplprops, boolean_t *is_ci) 2769185029Spjd{ 2770185029Spjd uint64_t sense = ZFS_PROP_UNDEFINED; 2771185029Spjd uint64_t norm = ZFS_PROP_UNDEFINED; 2772185029Spjd uint64_t u8 = ZFS_PROP_UNDEFINED; 2773185029Spjd 2774185029Spjd ASSERT(zplprops != NULL); 2775185029Spjd 2776185029Spjd /* 2777185029Spjd * Pull out creator prop choices, if any. 2778185029Spjd */ 2779185029Spjd if (createprops) { 2780185029Spjd (void) nvlist_lookup_uint64(createprops, 2781185029Spjd zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 2782185029Spjd (void) nvlist_lookup_uint64(createprops, 2783185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 2784185029Spjd (void) nvlist_remove_all(createprops, 2785185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 2786185029Spjd (void) nvlist_lookup_uint64(createprops, 2787185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 2788185029Spjd (void) nvlist_remove_all(createprops, 2789185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 2790185029Spjd (void) nvlist_lookup_uint64(createprops, 2791185029Spjd zfs_prop_to_name(ZFS_PROP_CASE), &sense); 2792185029Spjd (void) nvlist_remove_all(createprops, 2793185029Spjd zfs_prop_to_name(ZFS_PROP_CASE)); 2794185029Spjd } 2795185029Spjd 2796185029Spjd /* 2797185029Spjd * If the zpl version requested is whacky or the file system 2798185029Spjd * or pool is version is too "young" to support normalization 2799185029Spjd * and the creator tried to set a value for one of the props, 2800185029Spjd * error out. 2801185029Spjd */ 2802185029Spjd if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 2803185029Spjd (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 2804219089Spjd (zplver >= ZPL_VERSION_SA && !sa_ok) || 2805185029Spjd (zplver < ZPL_VERSION_NORMALIZATION && 2806185029Spjd (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 2807185029Spjd sense != ZFS_PROP_UNDEFINED))) 2808185029Spjd return (ENOTSUP); 2809185029Spjd 2810185029Spjd /* 2811185029Spjd * Put the version in the zplprops 2812185029Spjd */ 2813185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2814185029Spjd zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 2815185029Spjd 2816185029Spjd if (norm == ZFS_PROP_UNDEFINED) 2817185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 2818185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2819185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 2820185029Spjd 2821185029Spjd /* 2822185029Spjd * If we're normalizing, names must always be valid UTF-8 strings. 2823185029Spjd */ 2824185029Spjd if (norm) 2825185029Spjd u8 = 1; 2826185029Spjd if (u8 == ZFS_PROP_UNDEFINED) 2827185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 2828185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2829185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 2830185029Spjd 2831185029Spjd if (sense == ZFS_PROP_UNDEFINED) 2832185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 2833185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2834185029Spjd zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 2835185029Spjd 2836185029Spjd if (is_ci) 2837185029Spjd *is_ci = (sense == ZFS_CASE_INSENSITIVE); 2838185029Spjd 2839185029Spjd return (0); 2840185029Spjd} 2841185029Spjd 2842185029Spjdstatic int 2843185029Spjdzfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 2844185029Spjd nvlist_t *zplprops, boolean_t *is_ci) 2845185029Spjd{ 2846219089Spjd boolean_t fuids_ok, sa_ok; 2847185029Spjd uint64_t zplver = ZPL_VERSION; 2848185029Spjd objset_t *os = NULL; 2849185029Spjd char parentname[MAXNAMELEN]; 2850185029Spjd char *cp; 2851219089Spjd spa_t *spa; 2852219089Spjd uint64_t spa_vers; 2853185029Spjd int error; 2854185029Spjd 2855185029Spjd (void) strlcpy(parentname, dataset, sizeof (parentname)); 2856185029Spjd cp = strrchr(parentname, '/'); 2857185029Spjd ASSERT(cp != NULL); 2858185029Spjd cp[0] = '\0'; 2859185029Spjd 2860219089Spjd if ((error = spa_open(dataset, &spa, FTAG)) != 0) 2861219089Spjd return (error); 2862185029Spjd 2863219089Spjd spa_vers = spa_version(spa); 2864219089Spjd spa_close(spa, FTAG); 2865219089Spjd 2866219089Spjd zplver = zfs_zpl_version_map(spa_vers); 2867219089Spjd fuids_ok = (zplver >= ZPL_VERSION_FUID); 2868219089Spjd sa_ok = (zplver >= ZPL_VERSION_SA); 2869219089Spjd 2870185029Spjd /* 2871185029Spjd * Open parent object set so we can inherit zplprop values. 2872185029Spjd */ 2873219089Spjd if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0) 2874185029Spjd return (error); 2875185029Spjd 2876219089Spjd error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, sa_ok, createprops, 2877185029Spjd zplprops, is_ci); 2878219089Spjd dmu_objset_rele(os, FTAG); 2879185029Spjd return (error); 2880185029Spjd} 2881185029Spjd 2882185029Spjdstatic int 2883185029Spjdzfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 2884185029Spjd nvlist_t *zplprops, boolean_t *is_ci) 2885185029Spjd{ 2886219089Spjd boolean_t fuids_ok; 2887219089Spjd boolean_t sa_ok; 2888185029Spjd uint64_t zplver = ZPL_VERSION; 2889185029Spjd int error; 2890185029Spjd 2891219089Spjd zplver = zfs_zpl_version_map(spa_vers); 2892219089Spjd fuids_ok = (zplver >= ZPL_VERSION_FUID); 2893219089Spjd sa_ok = (zplver >= ZPL_VERSION_SA); 2894185029Spjd 2895219089Spjd error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, sa_ok, 2896219089Spjd createprops, zplprops, is_ci); 2897185029Spjd return (error); 2898185029Spjd} 2899185029Spjd 2900185029Spjd/* 2901185029Spjd * inputs: 2902185029Spjd * zc_objset_type type of objset to create (fs vs zvol) 2903185029Spjd * zc_name name of new objset 2904185029Spjd * zc_value name of snapshot to clone from (may be empty) 2905185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 2906185029Spjd * 2907185029Spjd * outputs: none 2908185029Spjd */ 2909185029Spjdstatic int 2910168404Spjdzfs_ioc_create(zfs_cmd_t *zc) 2911168404Spjd{ 2912168404Spjd objset_t *clone; 2913168404Spjd int error = 0; 2914185029Spjd zfs_creat_t zct; 2915185029Spjd nvlist_t *nvprops = NULL; 2916185029Spjd void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 2917168404Spjd dmu_objset_type_t type = zc->zc_objset_type; 2918168404Spjd 2919168404Spjd switch (type) { 2920168404Spjd 2921168404Spjd case DMU_OST_ZFS: 2922168404Spjd cbfunc = zfs_create_cb; 2923168404Spjd break; 2924168404Spjd 2925168404Spjd case DMU_OST_ZVOL: 2926168404Spjd cbfunc = zvol_create_cb; 2927168404Spjd break; 2928168404Spjd 2929168404Spjd default: 2930168404Spjd cbfunc = NULL; 2931185029Spjd break; 2932168404Spjd } 2933185029Spjd if (strchr(zc->zc_name, '@') || 2934185029Spjd strchr(zc->zc_name, '%')) 2935168404Spjd return (EINVAL); 2936168404Spjd 2937168404Spjd if (zc->zc_nvlist_src != 0 && 2938185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2939219089Spjd zc->zc_iflags, &nvprops)) != 0) 2940168404Spjd return (error); 2941168404Spjd 2942185029Spjd zct.zct_zplprops = NULL; 2943185029Spjd zct.zct_props = nvprops; 2944168404Spjd 2945168404Spjd if (zc->zc_value[0] != '\0') { 2946168404Spjd /* 2947168404Spjd * We're creating a clone of an existing snapshot. 2948168404Spjd */ 2949168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 2950168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 2951185029Spjd nvlist_free(nvprops); 2952168404Spjd return (EINVAL); 2953168404Spjd } 2954168404Spjd 2955219089Spjd error = dmu_objset_hold(zc->zc_value, FTAG, &clone); 2956168404Spjd if (error) { 2957185029Spjd nvlist_free(nvprops); 2958168404Spjd return (error); 2959168404Spjd } 2960185029Spjd 2961219089Spjd error = dmu_objset_clone(zc->zc_name, dmu_objset_ds(clone), 0); 2962219089Spjd dmu_objset_rele(clone, FTAG); 2963185029Spjd if (error) { 2964185029Spjd nvlist_free(nvprops); 2965185029Spjd return (error); 2966185029Spjd } 2967168404Spjd } else { 2968185029Spjd boolean_t is_insensitive = B_FALSE; 2969185029Spjd 2970168404Spjd if (cbfunc == NULL) { 2971185029Spjd nvlist_free(nvprops); 2972168404Spjd return (EINVAL); 2973168404Spjd } 2974168404Spjd 2975168404Spjd if (type == DMU_OST_ZVOL) { 2976168404Spjd uint64_t volsize, volblocksize; 2977168404Spjd 2978185029Spjd if (nvprops == NULL || 2979185029Spjd nvlist_lookup_uint64(nvprops, 2980168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 2981168404Spjd &volsize) != 0) { 2982185029Spjd nvlist_free(nvprops); 2983168404Spjd return (EINVAL); 2984168404Spjd } 2985168404Spjd 2986185029Spjd if ((error = nvlist_lookup_uint64(nvprops, 2987168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 2988168404Spjd &volblocksize)) != 0 && error != ENOENT) { 2989185029Spjd nvlist_free(nvprops); 2990168404Spjd return (EINVAL); 2991168404Spjd } 2992168404Spjd 2993168404Spjd if (error != 0) 2994168404Spjd volblocksize = zfs_prop_default_numeric( 2995168404Spjd ZFS_PROP_VOLBLOCKSIZE); 2996168404Spjd 2997168404Spjd if ((error = zvol_check_volblocksize( 2998168404Spjd volblocksize)) != 0 || 2999168404Spjd (error = zvol_check_volsize(volsize, 3000168404Spjd volblocksize)) != 0) { 3001185029Spjd nvlist_free(nvprops); 3002168404Spjd return (error); 3003168404Spjd } 3004185029Spjd } else if (type == DMU_OST_ZFS) { 3005185029Spjd int error; 3006185029Spjd 3007185029Spjd /* 3008185029Spjd * We have to have normalization and 3009185029Spjd * case-folding flags correct when we do the 3010185029Spjd * file system creation, so go figure them out 3011185029Spjd * now. 3012185029Spjd */ 3013185029Spjd VERIFY(nvlist_alloc(&zct.zct_zplprops, 3014185029Spjd NV_UNIQUE_NAME, KM_SLEEP) == 0); 3015185029Spjd error = zfs_fill_zplprops(zc->zc_name, nvprops, 3016185029Spjd zct.zct_zplprops, &is_insensitive); 3017185029Spjd if (error != 0) { 3018185029Spjd nvlist_free(nvprops); 3019185029Spjd nvlist_free(zct.zct_zplprops); 3020185029Spjd return (error); 3021185029Spjd } 3022168404Spjd } 3023219089Spjd error = dmu_objset_create(zc->zc_name, type, 3024185029Spjd is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 3025185029Spjd nvlist_free(zct.zct_zplprops); 3026168404Spjd } 3027168404Spjd 3028168404Spjd /* 3029168404Spjd * It would be nice to do this atomically. 3030168404Spjd */ 3031168404Spjd if (error == 0) { 3032219089Spjd error = zfs_set_prop_nvlist(zc->zc_name, ZPROP_SRC_LOCAL, 3033219089Spjd nvprops, NULL); 3034219089Spjd if (error != 0) 3035219089Spjd (void) dmu_objset_destroy(zc->zc_name, B_FALSE); 3036168404Spjd } 3037185029Spjd nvlist_free(nvprops); 3038219089Spjd#ifdef __FreeBSD__ 3039219089Spjd if (error == 0 && type == DMU_OST_ZVOL) 3040219089Spjd zvol_create_minors(zc->zc_name); 3041219089Spjd#endif 3042168404Spjd return (error); 3043168404Spjd} 3044168404Spjd 3045185029Spjd/* 3046185029Spjd * inputs: 3047185029Spjd * zc_name name of filesystem 3048185029Spjd * zc_value short name of snapshot 3049185029Spjd * zc_cookie recursive flag 3050209962Smm * zc_nvlist_src[_size] property list 3051185029Spjd * 3052219089Spjd * outputs: 3053219089Spjd * zc_value short snapname (i.e. part after the '@') 3054185029Spjd */ 3055185029Spjdstatic int 3056168404Spjdzfs_ioc_snapshot(zfs_cmd_t *zc) 3057168404Spjd{ 3058185029Spjd nvlist_t *nvprops = NULL; 3059185029Spjd int error; 3060185029Spjd boolean_t recursive = zc->zc_cookie; 3061185029Spjd 3062168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 3063168404Spjd return (EINVAL); 3064185029Spjd 3065185029Spjd if (zc->zc_nvlist_src != 0 && 3066185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3067219089Spjd zc->zc_iflags, &nvprops)) != 0) 3068185029Spjd return (error); 3069185029Spjd 3070209962Smm error = zfs_check_userprops(zc->zc_name, nvprops); 3071209962Smm if (error) 3072209962Smm goto out; 3073185029Spjd 3074219089Spjd if (!nvlist_empty(nvprops) && 3075209962Smm zfs_earlier_version(zc->zc_name, SPA_VERSION_SNAP_PROPS)) { 3076209962Smm error = ENOTSUP; 3077209962Smm goto out; 3078185029Spjd } 3079209962Smm 3080219089Spjd error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, NULL, 3081219089Spjd nvprops, recursive, B_FALSE, -1); 3082209962Smm 3083209962Smmout: 3084185029Spjd nvlist_free(nvprops); 3085185029Spjd return (error); 3086168404Spjd} 3087168404Spjd 3088168676Spjdint 3089219089Spjdzfs_unmount_snap(const char *name, void *arg) 3090168404Spjd{ 3091168404Spjd vfs_t *vfsp = NULL; 3092168404Spjd 3093185029Spjd if (arg) { 3094185029Spjd char *snapname = arg; 3095219089Spjd char *fullname = kmem_asprintf("%s@%s", name, snapname); 3096219089Spjd vfsp = zfs_get_vfs(fullname); 3097219089Spjd strfree(fullname); 3098168404Spjd } else if (strchr(name, '@')) { 3099168404Spjd vfsp = zfs_get_vfs(name); 3100168404Spjd } 3101168404Spjd 3102168404Spjd if (vfsp) { 3103168404Spjd /* 3104168404Spjd * Always force the unmount for snapshots. 3105168404Spjd */ 3106168404Spjd int flag = MS_FORCE; 3107168404Spjd int err; 3108168404Spjd 3109168404Spjd if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 3110168404Spjd VFS_RELE(vfsp); 3111168404Spjd return (err); 3112168404Spjd } 3113168404Spjd VFS_RELE(vfsp); 3114168404Spjd mtx_lock(&Giant); /* dounmount() */ 3115168404Spjd dounmount(vfsp, flag, curthread); 3116168404Spjd mtx_unlock(&Giant); /* dounmount() */ 3117168404Spjd } 3118168404Spjd return (0); 3119168404Spjd} 3120168404Spjd 3121185029Spjd/* 3122185029Spjd * inputs: 3123219089Spjd * zc_name name of filesystem 3124219089Spjd * zc_value short name of snapshot 3125219089Spjd * zc_defer_destroy mark for deferred destroy 3126185029Spjd * 3127185029Spjd * outputs: none 3128185029Spjd */ 3129168404Spjdstatic int 3130168404Spjdzfs_ioc_destroy_snaps(zfs_cmd_t *zc) 3131168404Spjd{ 3132168404Spjd int err; 3133168404Spjd 3134168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 3135168404Spjd return (EINVAL); 3136168404Spjd err = dmu_objset_find(zc->zc_name, 3137168404Spjd zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 3138168404Spjd if (err) 3139168404Spjd return (err); 3140219089Spjd return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value, 3141219089Spjd zc->zc_defer_destroy)); 3142168404Spjd} 3143168404Spjd 3144185029Spjd/* 3145185029Spjd * inputs: 3146185029Spjd * zc_name name of dataset to destroy 3147185029Spjd * zc_objset_type type of objset 3148219089Spjd * zc_defer_destroy mark for deferred destroy 3149185029Spjd * 3150185029Spjd * outputs: none 3151185029Spjd */ 3152168404Spjdstatic int 3153168404Spjdzfs_ioc_destroy(zfs_cmd_t *zc) 3154168404Spjd{ 3155219089Spjd int err; 3156168404Spjd if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 3157219089Spjd err = zfs_unmount_snap(zc->zc_name, NULL); 3158168404Spjd if (err) 3159168404Spjd return (err); 3160168404Spjd } 3161168404Spjd 3162219089Spjd err = dmu_objset_destroy(zc->zc_name, zc->zc_defer_destroy); 3163219089Spjd if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0) 3164219089Spjd (void) zvol_remove_minor(zc->zc_name); 3165219089Spjd return (err); 3166168404Spjd} 3167168404Spjd 3168185029Spjd/* 3169185029Spjd * inputs: 3170185029Spjd * zc_name name of dataset to rollback (to most recent snapshot) 3171185029Spjd * 3172185029Spjd * outputs: none 3173185029Spjd */ 3174168404Spjdstatic int 3175168404Spjdzfs_ioc_rollback(zfs_cmd_t *zc) 3176168404Spjd{ 3177219089Spjd dsl_dataset_t *ds, *clone; 3178185029Spjd int error; 3179219089Spjd zfsvfs_t *zfsvfs; 3180219089Spjd char *clone_name; 3181185029Spjd 3182219089Spjd error = dsl_dataset_hold(zc->zc_name, FTAG, &ds); 3183219089Spjd if (error) 3184219089Spjd return (error); 3185219089Spjd 3186219089Spjd /* must not be a snapshot */ 3187219089Spjd if (dsl_dataset_is_snapshot(ds)) { 3188219089Spjd dsl_dataset_rele(ds, FTAG); 3189219089Spjd return (EINVAL); 3190219089Spjd } 3191219089Spjd 3192219089Spjd /* must have a most recent snapshot */ 3193219089Spjd if (ds->ds_phys->ds_prev_snap_txg < TXG_INITIAL) { 3194219089Spjd dsl_dataset_rele(ds, FTAG); 3195219089Spjd return (EINVAL); 3196219089Spjd } 3197219089Spjd 3198185029Spjd /* 3199219089Spjd * Create clone of most recent snapshot. 3200185029Spjd */ 3201219089Spjd clone_name = kmem_asprintf("%s/%%rollback", zc->zc_name); 3202219089Spjd error = dmu_objset_clone(clone_name, ds->ds_prev, DS_FLAG_INCONSISTENT); 3203185029Spjd if (error) 3204219089Spjd goto out; 3205185029Spjd 3206219089Spjd error = dsl_dataset_own(clone_name, B_TRUE, FTAG, &clone); 3207219089Spjd if (error) 3208219089Spjd goto out; 3209219089Spjd 3210219089Spjd /* 3211219089Spjd * Do clone swap. 3212219089Spjd */ 3213209962Smm if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 3214219089Spjd error = zfs_suspend_fs(zfsvfs); 3215185029Spjd if (error == 0) { 3216185029Spjd int resume_err; 3217185029Spjd 3218219089Spjd if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 3219219089Spjd error = dsl_dataset_clone_swap(clone, ds, 3220219089Spjd B_TRUE); 3221219089Spjd dsl_dataset_disown(ds, FTAG); 3222219089Spjd ds = NULL; 3223219089Spjd } else { 3224219089Spjd error = EBUSY; 3225219089Spjd } 3226219089Spjd resume_err = zfs_resume_fs(zfsvfs, zc->zc_name); 3227185029Spjd error = error ? error : resume_err; 3228185029Spjd } 3229185029Spjd VFS_RELE(zfsvfs->z_vfs); 3230185029Spjd } else { 3231219089Spjd if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 3232219089Spjd error = dsl_dataset_clone_swap(clone, ds, B_TRUE); 3233219089Spjd dsl_dataset_disown(ds, FTAG); 3234219089Spjd ds = NULL; 3235219089Spjd } else { 3236219089Spjd error = EBUSY; 3237219089Spjd } 3238185029Spjd } 3239185029Spjd 3240219089Spjd /* 3241219089Spjd * Destroy clone (which also closes it). 3242219089Spjd */ 3243219089Spjd (void) dsl_dataset_destroy(clone, FTAG, B_FALSE); 3244219089Spjd 3245219089Spjdout: 3246219089Spjd strfree(clone_name); 3247219089Spjd if (ds) 3248219089Spjd dsl_dataset_rele(ds, FTAG); 3249185029Spjd return (error); 3250168404Spjd} 3251168404Spjd 3252185029Spjd/* 3253185029Spjd * inputs: 3254185029Spjd * zc_name old name of dataset 3255185029Spjd * zc_value new name of dataset 3256185029Spjd * zc_cookie recursive flag (only valid for snapshots) 3257185029Spjd * 3258185029Spjd * outputs: none 3259185029Spjd */ 3260168404Spjdstatic int 3261168404Spjdzfs_ioc_rename(zfs_cmd_t *zc) 3262168404Spjd{ 3263185029Spjd boolean_t recursive = zc->zc_cookie & 1; 3264168676Spjd 3265168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 3266185029Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 3267185029Spjd strchr(zc->zc_value, '%')) 3268168404Spjd return (EINVAL); 3269168404Spjd 3270168676Spjd /* 3271168676Spjd * Unmount snapshot unless we're doing a recursive rename, 3272168676Spjd * in which case the dataset code figures out which snapshots 3273168676Spjd * to unmount. 3274168676Spjd */ 3275168676Spjd if (!recursive && strchr(zc->zc_name, '@') != NULL && 3276168404Spjd zc->zc_objset_type == DMU_OST_ZFS) { 3277168404Spjd int err = zfs_unmount_snap(zc->zc_name, NULL); 3278168404Spjd if (err) 3279168404Spjd return (err); 3280168404Spjd } 3281168676Spjd return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 3282168404Spjd} 3283168404Spjd 3284219089Spjdstatic int 3285219089Spjdzfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) 3286185029Spjd{ 3287219089Spjd const char *propname = nvpair_name(pair); 3288219089Spjd boolean_t issnap = (strchr(dsname, '@') != NULL); 3289219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 3290219089Spjd uint64_t intval; 3291219089Spjd int err; 3292219089Spjd 3293219089Spjd if (prop == ZPROP_INVAL) { 3294219089Spjd if (zfs_prop_user(propname)) { 3295219089Spjd if (err = zfs_secpolicy_write_perms(dsname, 3296219089Spjd ZFS_DELEG_PERM_USERPROP, cr)) 3297219089Spjd return (err); 3298219089Spjd return (0); 3299219089Spjd } 3300219089Spjd 3301219089Spjd if (!issnap && zfs_prop_userquota(propname)) { 3302219089Spjd const char *perm = NULL; 3303219089Spjd const char *uq_prefix = 3304219089Spjd zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA]; 3305219089Spjd const char *gq_prefix = 3306219089Spjd zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA]; 3307219089Spjd 3308219089Spjd if (strncmp(propname, uq_prefix, 3309219089Spjd strlen(uq_prefix)) == 0) { 3310219089Spjd perm = ZFS_DELEG_PERM_USERQUOTA; 3311219089Spjd } else if (strncmp(propname, gq_prefix, 3312219089Spjd strlen(gq_prefix)) == 0) { 3313219089Spjd perm = ZFS_DELEG_PERM_GROUPQUOTA; 3314219089Spjd } else { 3315219089Spjd /* USERUSED and GROUPUSED are read-only */ 3316219089Spjd return (EINVAL); 3317219089Spjd } 3318219089Spjd 3319219089Spjd if (err = zfs_secpolicy_write_perms(dsname, perm, cr)) 3320219089Spjd return (err); 3321219089Spjd return (0); 3322219089Spjd } 3323219089Spjd 3324219089Spjd return (EINVAL); 3325219089Spjd } 3326219089Spjd 3327219089Spjd if (issnap) 3328219089Spjd return (EINVAL); 3329219089Spjd 3330219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 3331219089Spjd /* 3332219089Spjd * dsl_prop_get_all_impl() returns properties in this 3333219089Spjd * format. 3334219089Spjd */ 3335219089Spjd nvlist_t *attrs; 3336219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 3337219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 3338219089Spjd &pair) == 0); 3339219089Spjd } 3340219089Spjd 3341219089Spjd /* 3342219089Spjd * Check that this value is valid for this pool version 3343219089Spjd */ 3344219089Spjd switch (prop) { 3345219089Spjd case ZFS_PROP_COMPRESSION: 3346219089Spjd /* 3347219089Spjd * If the user specified gzip compression, make sure 3348219089Spjd * the SPA supports it. We ignore any errors here since 3349219089Spjd * we'll catch them later. 3350219089Spjd */ 3351219089Spjd if (nvpair_type(pair) == DATA_TYPE_UINT64 && 3352219089Spjd nvpair_value_uint64(pair, &intval) == 0) { 3353219089Spjd if (intval >= ZIO_COMPRESS_GZIP_1 && 3354219089Spjd intval <= ZIO_COMPRESS_GZIP_9 && 3355219089Spjd zfs_earlier_version(dsname, 3356219089Spjd SPA_VERSION_GZIP_COMPRESSION)) { 3357219089Spjd return (ENOTSUP); 3358219089Spjd } 3359219089Spjd 3360219089Spjd if (intval == ZIO_COMPRESS_ZLE && 3361219089Spjd zfs_earlier_version(dsname, 3362219089Spjd SPA_VERSION_ZLE_COMPRESSION)) 3363219089Spjd return (ENOTSUP); 3364219089Spjd 3365219089Spjd /* 3366219089Spjd * If this is a bootable dataset then 3367219089Spjd * verify that the compression algorithm 3368219089Spjd * is supported for booting. We must return 3369219089Spjd * something other than ENOTSUP since it 3370219089Spjd * implies a downrev pool version. 3371219089Spjd */ 3372219089Spjd if (zfs_is_bootfs(dsname) && 3373219089Spjd !BOOTFS_COMPRESS_VALID(intval)) { 3374219089Spjd return (ERANGE); 3375219089Spjd } 3376219089Spjd } 3377219089Spjd break; 3378219089Spjd 3379219089Spjd case ZFS_PROP_COPIES: 3380219089Spjd if (zfs_earlier_version(dsname, SPA_VERSION_DITTO_BLOCKS)) 3381219089Spjd return (ENOTSUP); 3382219089Spjd break; 3383219089Spjd 3384219089Spjd case ZFS_PROP_DEDUP: 3385219089Spjd if (zfs_earlier_version(dsname, SPA_VERSION_DEDUP)) 3386219089Spjd return (ENOTSUP); 3387219089Spjd break; 3388219089Spjd 3389219089Spjd case ZFS_PROP_SHARESMB: 3390219089Spjd if (zpl_earlier_version(dsname, ZPL_VERSION_FUID)) 3391219089Spjd return (ENOTSUP); 3392219089Spjd break; 3393219089Spjd 3394219089Spjd case ZFS_PROP_ACLINHERIT: 3395219089Spjd if (nvpair_type(pair) == DATA_TYPE_UINT64 && 3396219089Spjd nvpair_value_uint64(pair, &intval) == 0) { 3397219089Spjd if (intval == ZFS_ACL_PASSTHROUGH_X && 3398219089Spjd zfs_earlier_version(dsname, 3399219089Spjd SPA_VERSION_PASSTHROUGH_X)) 3400219089Spjd return (ENOTSUP); 3401219089Spjd } 3402219089Spjd break; 3403219089Spjd } 3404219089Spjd 3405219089Spjd return (zfs_secpolicy_setprop(dsname, prop, pair, CRED())); 3406219089Spjd} 3407219089Spjd 3408219089Spjd/* 3409219089Spjd * Removes properties from the given props list that fail permission checks 3410219089Spjd * needed to clear them and to restore them in case of a receive error. For each 3411219089Spjd * property, make sure we have both set and inherit permissions. 3412219089Spjd * 3413219089Spjd * Returns the first error encountered if any permission checks fail. If the 3414219089Spjd * caller provides a non-NULL errlist, it also gives the complete list of names 3415219089Spjd * of all the properties that failed a permission check along with the 3416219089Spjd * corresponding error numbers. The caller is responsible for freeing the 3417219089Spjd * returned errlist. 3418219089Spjd * 3419219089Spjd * If every property checks out successfully, zero is returned and the list 3420219089Spjd * pointed at by errlist is NULL. 3421219089Spjd */ 3422219089Spjdstatic int 3423219089Spjdzfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) 3424219089Spjd{ 3425185029Spjd zfs_cmd_t *zc; 3426219089Spjd nvpair_t *pair, *next_pair; 3427219089Spjd nvlist_t *errors; 3428219089Spjd int err, rv = 0; 3429185029Spjd 3430185029Spjd if (props == NULL) 3431219089Spjd return (0); 3432219089Spjd 3433219089Spjd VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 3434219089Spjd 3435185029Spjd zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 3436185029Spjd (void) strcpy(zc->zc_name, dataset); 3437219089Spjd pair = nvlist_next_nvpair(props, NULL); 3438219089Spjd while (pair != NULL) { 3439219089Spjd next_pair = nvlist_next_nvpair(props, pair); 3440219089Spjd 3441219089Spjd (void) strcpy(zc->zc_value, nvpair_name(pair)); 3442219089Spjd if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 || 3443219089Spjd (err = zfs_secpolicy_inherit(zc, CRED())) != 0) { 3444219089Spjd VERIFY(nvlist_remove_nvpair(props, pair) == 0); 3445219089Spjd VERIFY(nvlist_add_int32(errors, 3446219089Spjd zc->zc_value, err) == 0); 3447219089Spjd } 3448219089Spjd pair = next_pair; 3449185029Spjd } 3450185029Spjd kmem_free(zc, sizeof (zfs_cmd_t)); 3451219089Spjd 3452219089Spjd if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) { 3453219089Spjd nvlist_free(errors); 3454219089Spjd errors = NULL; 3455219089Spjd } else { 3456219089Spjd VERIFY(nvpair_value_int32(pair, &rv) == 0); 3457219089Spjd } 3458219089Spjd 3459219089Spjd if (errlist == NULL) 3460219089Spjd nvlist_free(errors); 3461219089Spjd else 3462219089Spjd *errlist = errors; 3463219089Spjd 3464219089Spjd return (rv); 3465185029Spjd} 3466185029Spjd 3467219089Spjdstatic boolean_t 3468219089Spjdpropval_equals(nvpair_t *p1, nvpair_t *p2) 3469219089Spjd{ 3470219089Spjd if (nvpair_type(p1) == DATA_TYPE_NVLIST) { 3471219089Spjd /* dsl_prop_get_all_impl() format */ 3472219089Spjd nvlist_t *attrs; 3473219089Spjd VERIFY(nvpair_value_nvlist(p1, &attrs) == 0); 3474219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 3475219089Spjd &p1) == 0); 3476219089Spjd } 3477219089Spjd 3478219089Spjd if (nvpair_type(p2) == DATA_TYPE_NVLIST) { 3479219089Spjd nvlist_t *attrs; 3480219089Spjd VERIFY(nvpair_value_nvlist(p2, &attrs) == 0); 3481219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 3482219089Spjd &p2) == 0); 3483219089Spjd } 3484219089Spjd 3485219089Spjd if (nvpair_type(p1) != nvpair_type(p2)) 3486219089Spjd return (B_FALSE); 3487219089Spjd 3488219089Spjd if (nvpair_type(p1) == DATA_TYPE_STRING) { 3489219089Spjd char *valstr1, *valstr2; 3490219089Spjd 3491219089Spjd VERIFY(nvpair_value_string(p1, (char **)&valstr1) == 0); 3492219089Spjd VERIFY(nvpair_value_string(p2, (char **)&valstr2) == 0); 3493219089Spjd return (strcmp(valstr1, valstr2) == 0); 3494219089Spjd } else { 3495219089Spjd uint64_t intval1, intval2; 3496219089Spjd 3497219089Spjd VERIFY(nvpair_value_uint64(p1, &intval1) == 0); 3498219089Spjd VERIFY(nvpair_value_uint64(p2, &intval2) == 0); 3499219089Spjd return (intval1 == intval2); 3500219089Spjd } 3501219089Spjd} 3502219089Spjd 3503185029Spjd/* 3504219089Spjd * Remove properties from props if they are not going to change (as determined 3505219089Spjd * by comparison with origprops). Remove them from origprops as well, since we 3506219089Spjd * do not need to clear or restore properties that won't change. 3507219089Spjd */ 3508219089Spjdstatic void 3509219089Spjdprops_reduce(nvlist_t *props, nvlist_t *origprops) 3510219089Spjd{ 3511219089Spjd nvpair_t *pair, *next_pair; 3512219089Spjd 3513219089Spjd if (origprops == NULL) 3514219089Spjd return; /* all props need to be received */ 3515219089Spjd 3516219089Spjd pair = nvlist_next_nvpair(props, NULL); 3517219089Spjd while (pair != NULL) { 3518219089Spjd const char *propname = nvpair_name(pair); 3519219089Spjd nvpair_t *match; 3520219089Spjd 3521219089Spjd next_pair = nvlist_next_nvpair(props, pair); 3522219089Spjd 3523219089Spjd if ((nvlist_lookup_nvpair(origprops, propname, 3524219089Spjd &match) != 0) || !propval_equals(pair, match)) 3525219089Spjd goto next; /* need to set received value */ 3526219089Spjd 3527219089Spjd /* don't clear the existing received value */ 3528219089Spjd (void) nvlist_remove_nvpair(origprops, match); 3529219089Spjd /* don't bother receiving the property */ 3530219089Spjd (void) nvlist_remove_nvpair(props, pair); 3531219089Spjdnext: 3532219089Spjd pair = next_pair; 3533219089Spjd } 3534219089Spjd} 3535219089Spjd 3536219089Spjd#ifdef DEBUG 3537219089Spjdstatic boolean_t zfs_ioc_recv_inject_err; 3538219089Spjd#endif 3539219089Spjd 3540219089Spjd/* 3541185029Spjd * inputs: 3542185029Spjd * zc_name name of containing filesystem 3543185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 3544185029Spjd * zc_value name of snapshot to create 3545185029Spjd * zc_string name of clone origin (if DRR_FLAG_CLONE) 3546185029Spjd * zc_cookie file descriptor to recv from 3547185029Spjd * zc_begin_record the BEGIN record of the stream (not byteswapped) 3548185029Spjd * zc_guid force flag 3549219089Spjd * zc_cleanup_fd cleanup-on-exit file descriptor 3550219089Spjd * zc_action_handle handle for this guid/ds mapping (or zero on first call) 3551185029Spjd * 3552185029Spjd * outputs: 3553185029Spjd * zc_cookie number of bytes read 3554219089Spjd * zc_nvlist_dst{_size} error for each unapplied received property 3555219089Spjd * zc_obj zprop_errflags_t 3556219089Spjd * zc_action_handle handle for this guid/ds mapping 3557185029Spjd */ 3558168404Spjdstatic int 3559185029Spjdzfs_ioc_recv(zfs_cmd_t *zc) 3560168404Spjd{ 3561185029Spjd file_t *fp; 3562185029Spjd objset_t *os; 3563185029Spjd dmu_recv_cookie_t drc; 3564185029Spjd boolean_t force = (boolean_t)zc->zc_guid; 3565219089Spjd int fd; 3566219089Spjd int error = 0; 3567219089Spjd int props_error = 0; 3568219089Spjd nvlist_t *errors; 3569185029Spjd offset_t off; 3570219089Spjd nvlist_t *props = NULL; /* sent properties */ 3571219089Spjd nvlist_t *origprops = NULL; /* existing properties */ 3572185029Spjd objset_t *origin = NULL; 3573185029Spjd char *tosnap; 3574185029Spjd char tofs[ZFS_MAXNAMELEN]; 3575219089Spjd boolean_t first_recvd_props = B_FALSE; 3576168404Spjd 3577168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 3578185029Spjd strchr(zc->zc_value, '@') == NULL || 3579185029Spjd strchr(zc->zc_value, '%')) 3580168404Spjd return (EINVAL); 3581168404Spjd 3582185029Spjd (void) strcpy(tofs, zc->zc_value); 3583185029Spjd tosnap = strchr(tofs, '@'); 3584219089Spjd *tosnap++ = '\0'; 3585185029Spjd 3586185029Spjd if (zc->zc_nvlist_src != 0 && 3587185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3588219089Spjd zc->zc_iflags, &props)) != 0) 3589168404Spjd return (error); 3590168404Spjd 3591185029Spjd fd = zc->zc_cookie; 3592219089Spjd fp = getf(fd); 3593185029Spjd if (fp == NULL) { 3594185029Spjd nvlist_free(props); 3595185029Spjd return (EBADF); 3596185029Spjd } 3597168404Spjd 3598219089Spjd VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 3599219089Spjd 3600219089Spjd if (props && dmu_objset_hold(tofs, FTAG, &os) == 0) { 3601219089Spjd if ((spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS) && 3602219089Spjd !dsl_prop_get_hasrecvd(os)) { 3603219089Spjd first_recvd_props = B_TRUE; 3604185029Spjd } 3605219089Spjd 3606185029Spjd /* 3607219089Spjd * If new received properties are supplied, they are to 3608219089Spjd * completely replace the existing received properties, so stash 3609219089Spjd * away the existing ones. 3610185029Spjd */ 3611219089Spjd if (dsl_prop_get_received(os, &origprops) == 0) { 3612219089Spjd nvlist_t *errlist = NULL; 3613219089Spjd /* 3614219089Spjd * Don't bother writing a property if its value won't 3615219089Spjd * change (and avoid the unnecessary security checks). 3616219089Spjd * 3617219089Spjd * The first receive after SPA_VERSION_RECVD_PROPS is a 3618219089Spjd * special case where we blow away all local properties 3619219089Spjd * regardless. 3620219089Spjd */ 3621219089Spjd if (!first_recvd_props) 3622219089Spjd props_reduce(props, origprops); 3623219089Spjd if (zfs_check_clearable(tofs, origprops, 3624219089Spjd &errlist) != 0) 3625219089Spjd (void) nvlist_merge(errors, errlist, 0); 3626219089Spjd nvlist_free(errlist); 3627219089Spjd } 3628185029Spjd 3629219089Spjd dmu_objset_rele(os, FTAG); 3630185029Spjd } 3631185029Spjd 3632185029Spjd if (zc->zc_string[0]) { 3633219089Spjd error = dmu_objset_hold(zc->zc_string, FTAG, &origin); 3634185029Spjd if (error) 3635185029Spjd goto out; 3636185029Spjd } 3637185029Spjd 3638219089Spjd error = dmu_recv_begin(tofs, tosnap, zc->zc_top_ds, 3639219089Spjd &zc->zc_begin_record, force, origin, &drc); 3640185029Spjd if (origin) 3641219089Spjd dmu_objset_rele(origin, FTAG); 3642185029Spjd if (error) 3643185029Spjd goto out; 3644185029Spjd 3645185029Spjd /* 3646219089Spjd * Set properties before we receive the stream so that they are applied 3647219089Spjd * to the new data. Note that we must call dmu_recv_stream() if 3648219089Spjd * dmu_recv_begin() succeeds. 3649185029Spjd */ 3650185029Spjd if (props) { 3651219089Spjd nvlist_t *errlist; 3652219089Spjd 3653219089Spjd if (dmu_objset_from_ds(drc.drc_logical_ds, &os) == 0) { 3654219089Spjd if (drc.drc_newfs) { 3655219089Spjd if (spa_version(os->os_spa) >= 3656219089Spjd SPA_VERSION_RECVD_PROPS) 3657219089Spjd first_recvd_props = B_TRUE; 3658219089Spjd } else if (origprops != NULL) { 3659219089Spjd if (clear_received_props(os, tofs, origprops, 3660219089Spjd first_recvd_props ? NULL : props) != 0) 3661219089Spjd zc->zc_obj |= ZPROP_ERR_NOCLEAR; 3662219089Spjd } else { 3663219089Spjd zc->zc_obj |= ZPROP_ERR_NOCLEAR; 3664219089Spjd } 3665219089Spjd dsl_prop_set_hasrecvd(os); 3666219089Spjd } else if (!drc.drc_newfs) { 3667219089Spjd zc->zc_obj |= ZPROP_ERR_NOCLEAR; 3668219089Spjd } 3669219089Spjd 3670219089Spjd (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, 3671219089Spjd props, &errlist); 3672219089Spjd (void) nvlist_merge(errors, errlist, 0); 3673219089Spjd nvlist_free(errlist); 3674219089Spjd } 3675219089Spjd 3676219089Spjd if (fit_error_list(zc, &errors) != 0 || put_nvlist(zc, errors) != 0) { 3677185029Spjd /* 3678219089Spjd * Caller made zc->zc_nvlist_dst less than the minimum expected 3679219089Spjd * size or supplied an invalid address. 3680185029Spjd */ 3681219089Spjd props_error = EINVAL; 3682185029Spjd } 3683185029Spjd 3684185029Spjd off = fp->f_offset; 3685219089Spjd error = dmu_recv_stream(&drc, fp, &off, zc->zc_cleanup_fd, 3686219089Spjd &zc->zc_action_handle); 3687185029Spjd 3688219089Spjd if (error == 0) { 3689219089Spjd zfsvfs_t *zfsvfs = NULL; 3690185029Spjd 3691219089Spjd if (getzfsvfs(tofs, &zfsvfs) == 0) { 3692219089Spjd /* online recv */ 3693219089Spjd int end_err; 3694185029Spjd 3695219089Spjd error = zfs_suspend_fs(zfsvfs); 3696219089Spjd /* 3697219089Spjd * If the suspend fails, then the recv_end will 3698219089Spjd * likely also fail, and clean up after itself. 3699219089Spjd */ 3700219089Spjd end_err = dmu_recv_end(&drc); 3701219089Spjd if (error == 0) 3702219089Spjd error = zfs_resume_fs(zfsvfs, tofs); 3703219089Spjd error = error ? error : end_err; 3704219089Spjd VFS_RELE(zfsvfs->z_vfs); 3705219089Spjd } else { 3706185029Spjd error = dmu_recv_end(&drc); 3707185029Spjd } 3708185029Spjd } 3709185029Spjd 3710185029Spjd zc->zc_cookie = off - fp->f_offset; 3711185029Spjd if (off >= 0 && off <= MAXOFFSET_T) 3712185029Spjd fp->f_offset = off; 3713185029Spjd 3714219089Spjd#ifdef DEBUG 3715219089Spjd if (zfs_ioc_recv_inject_err) { 3716219089Spjd zfs_ioc_recv_inject_err = B_FALSE; 3717219089Spjd error = 1; 3718219089Spjd } 3719219089Spjd#endif 3720185029Spjd /* 3721185029Spjd * On error, restore the original props. 3722185029Spjd */ 3723185029Spjd if (error && props) { 3724219089Spjd if (dmu_objset_hold(tofs, FTAG, &os) == 0) { 3725219089Spjd if (clear_received_props(os, tofs, props, NULL) != 0) { 3726219089Spjd /* 3727219089Spjd * We failed to clear the received properties. 3728219089Spjd * Since we may have left a $recvd value on the 3729219089Spjd * system, we can't clear the $hasrecvd flag. 3730219089Spjd */ 3731219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3732219089Spjd } else if (first_recvd_props) { 3733219089Spjd dsl_prop_unset_hasrecvd(os); 3734219089Spjd } 3735219089Spjd dmu_objset_rele(os, FTAG); 3736219089Spjd } else if (!drc.drc_newfs) { 3737219089Spjd /* We failed to clear the received properties. */ 3738219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3739219089Spjd } 3740219089Spjd 3741219089Spjd if (origprops == NULL && !drc.drc_newfs) { 3742219089Spjd /* We failed to stash the original properties. */ 3743219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3744219089Spjd } 3745219089Spjd 3746219089Spjd /* 3747219089Spjd * dsl_props_set() will not convert RECEIVED to LOCAL on or 3748219089Spjd * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL 3749219089Spjd * explictly if we're restoring local properties cleared in the 3750219089Spjd * first new-style receive. 3751219089Spjd */ 3752219089Spjd if (origprops != NULL && 3753219089Spjd zfs_set_prop_nvlist(tofs, (first_recvd_props ? 3754219089Spjd ZPROP_SRC_LOCAL : ZPROP_SRC_RECEIVED), 3755219089Spjd origprops, NULL) != 0) { 3756219089Spjd /* 3757219089Spjd * We stashed the original properties but failed to 3758219089Spjd * restore them. 3759219089Spjd */ 3760219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3761219089Spjd } 3762185029Spjd } 3763185029Spjdout: 3764185029Spjd nvlist_free(props); 3765185029Spjd nvlist_free(origprops); 3766219089Spjd nvlist_free(errors); 3767219089Spjd releasef(fd); 3768219089Spjd 3769219089Spjd if (error == 0) 3770219089Spjd error = props_error; 3771219089Spjd 3772168404Spjd return (error); 3773168404Spjd} 3774168404Spjd 3775185029Spjd/* 3776185029Spjd * inputs: 3777185029Spjd * zc_name name of snapshot to send 3778185029Spjd * zc_cookie file descriptor to send stream to 3779219089Spjd * zc_obj fromorigin flag (mutually exclusive with zc_fromobj) 3780219089Spjd * zc_sendobj objsetid of snapshot to send 3781219089Spjd * zc_fromobj objsetid of incremental fromsnap (may be zero) 3782185029Spjd * 3783185029Spjd * outputs: none 3784185029Spjd */ 3785168404Spjdstatic int 3786185029Spjdzfs_ioc_send(zfs_cmd_t *zc) 3787168404Spjd{ 3788168404Spjd objset_t *fromsnap = NULL; 3789168404Spjd objset_t *tosnap; 3790185029Spjd file_t *fp; 3791185029Spjd int error; 3792185029Spjd offset_t off; 3793219089Spjd dsl_dataset_t *ds; 3794219089Spjd dsl_dataset_t *dsfrom = NULL; 3795219089Spjd spa_t *spa; 3796219089Spjd dsl_pool_t *dp; 3797168404Spjd 3798219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 3799168404Spjd if (error) 3800168404Spjd return (error); 3801168404Spjd 3802219089Spjd dp = spa_get_dsl(spa); 3803219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 3804219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 3805219089Spjd rw_exit(&dp->dp_config_rwlock); 3806219089Spjd if (error) { 3807219089Spjd spa_close(spa, FTAG); 3808219089Spjd return (error); 3809219089Spjd } 3810168404Spjd 3811219089Spjd error = dmu_objset_from_ds(ds, &tosnap); 3812219089Spjd if (error) { 3813219089Spjd dsl_dataset_rele(ds, FTAG); 3814219089Spjd spa_close(spa, FTAG); 3815219089Spjd return (error); 3816219089Spjd } 3817219089Spjd 3818219089Spjd if (zc->zc_fromobj != 0) { 3819219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 3820219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_fromobj, FTAG, &dsfrom); 3821219089Spjd rw_exit(&dp->dp_config_rwlock); 3822219089Spjd spa_close(spa, FTAG); 3823168404Spjd if (error) { 3824219089Spjd dsl_dataset_rele(ds, FTAG); 3825168404Spjd return (error); 3826168404Spjd } 3827219089Spjd error = dmu_objset_from_ds(dsfrom, &fromsnap); 3828219089Spjd if (error) { 3829219089Spjd dsl_dataset_rele(dsfrom, FTAG); 3830219089Spjd dsl_dataset_rele(ds, FTAG); 3831219089Spjd return (error); 3832219089Spjd } 3833219089Spjd } else { 3834219089Spjd spa_close(spa, FTAG); 3835168404Spjd } 3836168404Spjd 3837219089Spjd fp = getf(zc->zc_cookie); 3838185029Spjd if (fp == NULL) { 3839219089Spjd dsl_dataset_rele(ds, FTAG); 3840219089Spjd if (dsfrom) 3841219089Spjd dsl_dataset_rele(dsfrom, FTAG); 3842185029Spjd return (EBADF); 3843168404Spjd } 3844168404Spjd 3845185029Spjd off = fp->f_offset; 3846185029Spjd error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp, &off); 3847168404Spjd 3848185029Spjd if (off >= 0 && off <= MAXOFFSET_T) 3849185029Spjd fp->f_offset = off; 3850219089Spjd releasef(zc->zc_cookie); 3851219089Spjd if (dsfrom) 3852219089Spjd dsl_dataset_rele(dsfrom, FTAG); 3853219089Spjd dsl_dataset_rele(ds, FTAG); 3854168404Spjd return (error); 3855168404Spjd} 3856168404Spjd 3857168404Spjdstatic int 3858168404Spjdzfs_ioc_inject_fault(zfs_cmd_t *zc) 3859168404Spjd{ 3860168404Spjd int id, error; 3861168404Spjd 3862168404Spjd error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 3863168404Spjd &zc->zc_inject_record); 3864168404Spjd 3865168404Spjd if (error == 0) 3866168404Spjd zc->zc_guid = (uint64_t)id; 3867168404Spjd 3868168404Spjd return (error); 3869168404Spjd} 3870168404Spjd 3871168404Spjdstatic int 3872168404Spjdzfs_ioc_clear_fault(zfs_cmd_t *zc) 3873168404Spjd{ 3874168404Spjd return (zio_clear_fault((int)zc->zc_guid)); 3875168404Spjd} 3876168404Spjd 3877168404Spjdstatic int 3878168404Spjdzfs_ioc_inject_list_next(zfs_cmd_t *zc) 3879168404Spjd{ 3880168404Spjd int id = (int)zc->zc_guid; 3881168404Spjd int error; 3882168404Spjd 3883168404Spjd error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 3884168404Spjd &zc->zc_inject_record); 3885168404Spjd 3886168404Spjd zc->zc_guid = id; 3887168404Spjd 3888168404Spjd return (error); 3889168404Spjd} 3890168404Spjd 3891168404Spjdstatic int 3892168404Spjdzfs_ioc_error_log(zfs_cmd_t *zc) 3893168404Spjd{ 3894168404Spjd spa_t *spa; 3895168404Spjd int error; 3896168404Spjd size_t count = (size_t)zc->zc_nvlist_dst_size; 3897168404Spjd 3898168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 3899168404Spjd return (error); 3900168404Spjd 3901168404Spjd error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 3902168404Spjd &count); 3903168404Spjd if (error == 0) 3904168404Spjd zc->zc_nvlist_dst_size = count; 3905168404Spjd else 3906168404Spjd zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 3907168404Spjd 3908168404Spjd spa_close(spa, FTAG); 3909168404Spjd 3910168404Spjd return (error); 3911168404Spjd} 3912168404Spjd 3913168404Spjdstatic int 3914168404Spjdzfs_ioc_clear(zfs_cmd_t *zc) 3915168404Spjd{ 3916168404Spjd spa_t *spa; 3917168404Spjd vdev_t *vd; 3918168404Spjd int error; 3919168404Spjd 3920185029Spjd /* 3921185029Spjd * On zpool clear we also fix up missing slogs 3922185029Spjd */ 3923185029Spjd mutex_enter(&spa_namespace_lock); 3924185029Spjd spa = spa_lookup(zc->zc_name); 3925185029Spjd if (spa == NULL) { 3926185029Spjd mutex_exit(&spa_namespace_lock); 3927185029Spjd return (EIO); 3928185029Spjd } 3929219089Spjd if (spa_get_log_state(spa) == SPA_LOG_MISSING) { 3930185029Spjd /* we need to let spa_open/spa_load clear the chains */ 3931219089Spjd spa_set_log_state(spa, SPA_LOG_CLEAR); 3932185029Spjd } 3933219089Spjd spa->spa_last_open_failed = 0; 3934185029Spjd mutex_exit(&spa_namespace_lock); 3935185029Spjd 3936219089Spjd if (zc->zc_cookie & ZPOOL_NO_REWIND) { 3937219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 3938219089Spjd } else { 3939219089Spjd nvlist_t *policy; 3940219089Spjd nvlist_t *config = NULL; 3941219089Spjd 3942219089Spjd if (zc->zc_nvlist_src == 0) 3943219089Spjd return (EINVAL); 3944219089Spjd 3945219089Spjd if ((error = get_nvlist(zc->zc_nvlist_src, 3946219089Spjd zc->zc_nvlist_src_size, zc->zc_iflags, &policy)) == 0) { 3947219089Spjd error = spa_open_rewind(zc->zc_name, &spa, FTAG, 3948219089Spjd policy, &config); 3949219089Spjd if (config != NULL) { 3950219089Spjd int err; 3951219089Spjd 3952219089Spjd if ((err = put_nvlist(zc, config)) != 0) 3953219089Spjd error = err; 3954219089Spjd nvlist_free(config); 3955219089Spjd } 3956219089Spjd nvlist_free(policy); 3957219089Spjd } 3958219089Spjd } 3959219089Spjd 3960219089Spjd if (error) 3961168404Spjd return (error); 3962168404Spjd 3963219089Spjd spa_vdev_state_enter(spa, SCL_NONE); 3964168404Spjd 3965168404Spjd if (zc->zc_guid == 0) { 3966168404Spjd vd = NULL; 3967185029Spjd } else { 3968185029Spjd vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 3969185029Spjd if (vd == NULL) { 3970185029Spjd (void) spa_vdev_state_exit(spa, NULL, ENODEV); 3971185029Spjd spa_close(spa, FTAG); 3972185029Spjd return (ENODEV); 3973185029Spjd } 3974168404Spjd } 3975168404Spjd 3976168404Spjd vdev_clear(spa, vd); 3977168404Spjd 3978185029Spjd (void) spa_vdev_state_exit(spa, NULL, 0); 3979168404Spjd 3980185029Spjd /* 3981185029Spjd * Resume any suspended I/Os. 3982185029Spjd */ 3983209962Smm if (zio_resume(spa) != 0) 3984209962Smm error = EIO; 3985185029Spjd 3986168404Spjd spa_close(spa, FTAG); 3987168404Spjd 3988209962Smm return (error); 3989168404Spjd} 3990168404Spjd 3991185029Spjd/* 3992185029Spjd * inputs: 3993185029Spjd * zc_name name of filesystem 3994185029Spjd * zc_value name of origin snapshot 3995185029Spjd * 3996219089Spjd * outputs: 3997219089Spjd * zc_string name of conflicting snapshot, if there is one 3998185029Spjd */ 3999168404Spjdstatic int 4000168404Spjdzfs_ioc_promote(zfs_cmd_t *zc) 4001168404Spjd{ 4002168404Spjd char *cp; 4003168404Spjd 4004168404Spjd /* 4005168404Spjd * We don't need to unmount *all* the origin fs's snapshots, but 4006168404Spjd * it's easier. 4007168404Spjd */ 4008168404Spjd cp = strchr(zc->zc_value, '@'); 4009168404Spjd if (cp) 4010168404Spjd *cp = '\0'; 4011168404Spjd (void) dmu_objset_find(zc->zc_value, 4012168404Spjd zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 4013219089Spjd return (dsl_dataset_promote(zc->zc_name, zc->zc_string)); 4014168404Spjd} 4015168404Spjd 4016185029Spjd/* 4017209962Smm * Retrieve a single {user|group}{used|quota}@... property. 4018209962Smm * 4019209962Smm * inputs: 4020209962Smm * zc_name name of filesystem 4021209962Smm * zc_objset_type zfs_userquota_prop_t 4022209962Smm * zc_value domain name (eg. "S-1-234-567-89") 4023209962Smm * zc_guid RID/UID/GID 4024209962Smm * 4025209962Smm * outputs: 4026209962Smm * zc_cookie property value 4027209962Smm */ 4028209962Smmstatic int 4029209962Smmzfs_ioc_userspace_one(zfs_cmd_t *zc) 4030209962Smm{ 4031209962Smm zfsvfs_t *zfsvfs; 4032209962Smm int error; 4033209962Smm 4034209962Smm if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 4035209962Smm return (EINVAL); 4036209962Smm 4037219089Spjd error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 4038209962Smm if (error) 4039209962Smm return (error); 4040209962Smm 4041209962Smm error = zfs_userspace_one(zfsvfs, 4042209962Smm zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 4043209962Smm zfsvfs_rele(zfsvfs, FTAG); 4044209962Smm 4045209962Smm return (error); 4046209962Smm} 4047209962Smm 4048209962Smm/* 4049209962Smm * inputs: 4050209962Smm * zc_name name of filesystem 4051209962Smm * zc_cookie zap cursor 4052209962Smm * zc_objset_type zfs_userquota_prop_t 4053209962Smm * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 4054209962Smm * 4055209962Smm * outputs: 4056209962Smm * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 4057209962Smm * zc_cookie zap cursor 4058209962Smm */ 4059209962Smmstatic int 4060209962Smmzfs_ioc_userspace_many(zfs_cmd_t *zc) 4061209962Smm{ 4062209962Smm zfsvfs_t *zfsvfs; 4063219089Spjd int bufsize = zc->zc_nvlist_dst_size; 4064209962Smm 4065219089Spjd if (bufsize <= 0) 4066219089Spjd return (ENOMEM); 4067219089Spjd 4068219089Spjd int error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 4069209962Smm if (error) 4070209962Smm return (error); 4071209962Smm 4072209962Smm void *buf = kmem_alloc(bufsize, KM_SLEEP); 4073209962Smm 4074209962Smm error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 4075209962Smm buf, &zc->zc_nvlist_dst_size); 4076209962Smm 4077209962Smm if (error == 0) { 4078221409Smarius error = ddi_copyout(buf, 4079209962Smm (void *)(uintptr_t)zc->zc_nvlist_dst, 4080221409Smarius zc->zc_nvlist_dst_size, zc->zc_iflags); 4081209962Smm } 4082209962Smm kmem_free(buf, bufsize); 4083209962Smm zfsvfs_rele(zfsvfs, FTAG); 4084209962Smm 4085209962Smm return (error); 4086209962Smm} 4087209962Smm 4088209962Smm/* 4089209962Smm * inputs: 4090209962Smm * zc_name name of filesystem 4091209962Smm * 4092209962Smm * outputs: 4093209962Smm * none 4094209962Smm */ 4095209962Smmstatic int 4096209962Smmzfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 4097209962Smm{ 4098209962Smm objset_t *os; 4099219089Spjd int error = 0; 4100209962Smm zfsvfs_t *zfsvfs; 4101209962Smm 4102209962Smm if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 4103219089Spjd if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { 4104209962Smm /* 4105209962Smm * If userused is not enabled, it may be because the 4106209962Smm * objset needs to be closed & reopened (to grow the 4107209962Smm * objset_phys_t). Suspend/resume the fs will do that. 4108209962Smm */ 4109219089Spjd error = zfs_suspend_fs(zfsvfs); 4110219089Spjd if (error == 0) 4111219089Spjd error = zfs_resume_fs(zfsvfs, zc->zc_name); 4112209962Smm } 4113209962Smm if (error == 0) 4114209962Smm error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 4115209962Smm VFS_RELE(zfsvfs->z_vfs); 4116209962Smm } else { 4117219089Spjd /* XXX kind of reading contents without owning */ 4118219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &os); 4119209962Smm if (error) 4120209962Smm return (error); 4121209962Smm 4122209962Smm error = dmu_objset_userspace_upgrade(os); 4123219089Spjd dmu_objset_rele(os, FTAG); 4124209962Smm } 4125209962Smm 4126209962Smm return (error); 4127209962Smm} 4128209962Smm 4129209962Smm#ifdef sun 4130209962Smm/* 4131185029Spjd * We don't want to have a hard dependency 4132185029Spjd * against some special symbols in sharefs 4133185029Spjd * nfs, and smbsrv. Determine them if needed when 4134185029Spjd * the first file system is shared. 4135185029Spjd * Neither sharefs, nfs or smbsrv are unloadable modules. 4136185029Spjd */ 4137185029Spjdint (*znfsexport_fs)(void *arg); 4138185029Spjdint (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 4139185029Spjdint (*zsmbexport_fs)(void *arg, boolean_t add_share); 4140185029Spjd 4141185029Spjdint zfs_nfsshare_inited; 4142185029Spjdint zfs_smbshare_inited; 4143185029Spjd 4144185029Spjdddi_modhandle_t nfs_mod; 4145185029Spjdddi_modhandle_t sharefs_mod; 4146185029Spjdddi_modhandle_t smbsrv_mod; 4147209962Smm#endif /* sun */ 4148185029Spjdkmutex_t zfs_share_lock; 4149185029Spjd 4150209962Smm#ifdef sun 4151168404Spjdstatic int 4152185029Spjdzfs_init_sharefs() 4153185029Spjd{ 4154185029Spjd int error; 4155185029Spjd 4156185029Spjd ASSERT(MUTEX_HELD(&zfs_share_lock)); 4157185029Spjd /* Both NFS and SMB shares also require sharetab support. */ 4158185029Spjd if (sharefs_mod == NULL && ((sharefs_mod = 4159185029Spjd ddi_modopen("fs/sharefs", 4160185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 4161185029Spjd return (ENOSYS); 4162185029Spjd } 4163185029Spjd if (zshare_fs == NULL && ((zshare_fs = 4164185029Spjd (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 4165185029Spjd ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 4166185029Spjd return (ENOSYS); 4167185029Spjd } 4168185029Spjd return (0); 4169185029Spjd} 4170219089Spjd#endif /* sun */ 4171185029Spjd 4172185029Spjdstatic int 4173185029Spjdzfs_ioc_share(zfs_cmd_t *zc) 4174185029Spjd{ 4175209962Smm#ifdef sun 4176185029Spjd int error; 4177185029Spjd int opcode; 4178185029Spjd 4179185029Spjd switch (zc->zc_share.z_sharetype) { 4180185029Spjd case ZFS_SHARE_NFS: 4181185029Spjd case ZFS_UNSHARE_NFS: 4182185029Spjd if (zfs_nfsshare_inited == 0) { 4183185029Spjd mutex_enter(&zfs_share_lock); 4184185029Spjd if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 4185185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 4186185029Spjd mutex_exit(&zfs_share_lock); 4187185029Spjd return (ENOSYS); 4188185029Spjd } 4189185029Spjd if (znfsexport_fs == NULL && 4190185029Spjd ((znfsexport_fs = (int (*)(void *)) 4191185029Spjd ddi_modsym(nfs_mod, 4192185029Spjd "nfs_export", &error)) == NULL)) { 4193185029Spjd mutex_exit(&zfs_share_lock); 4194185029Spjd return (ENOSYS); 4195185029Spjd } 4196185029Spjd error = zfs_init_sharefs(); 4197185029Spjd if (error) { 4198185029Spjd mutex_exit(&zfs_share_lock); 4199185029Spjd return (ENOSYS); 4200185029Spjd } 4201185029Spjd zfs_nfsshare_inited = 1; 4202185029Spjd mutex_exit(&zfs_share_lock); 4203185029Spjd } 4204185029Spjd break; 4205185029Spjd case ZFS_SHARE_SMB: 4206185029Spjd case ZFS_UNSHARE_SMB: 4207185029Spjd if (zfs_smbshare_inited == 0) { 4208185029Spjd mutex_enter(&zfs_share_lock); 4209185029Spjd if (smbsrv_mod == NULL && ((smbsrv_mod = 4210185029Spjd ddi_modopen("drv/smbsrv", 4211185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 4212185029Spjd mutex_exit(&zfs_share_lock); 4213185029Spjd return (ENOSYS); 4214185029Spjd } 4215185029Spjd if (zsmbexport_fs == NULL && ((zsmbexport_fs = 4216185029Spjd (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 4217185029Spjd "smb_server_share", &error)) == NULL)) { 4218185029Spjd mutex_exit(&zfs_share_lock); 4219185029Spjd return (ENOSYS); 4220185029Spjd } 4221185029Spjd error = zfs_init_sharefs(); 4222185029Spjd if (error) { 4223185029Spjd mutex_exit(&zfs_share_lock); 4224185029Spjd return (ENOSYS); 4225185029Spjd } 4226185029Spjd zfs_smbshare_inited = 1; 4227185029Spjd mutex_exit(&zfs_share_lock); 4228185029Spjd } 4229185029Spjd break; 4230185029Spjd default: 4231185029Spjd return (EINVAL); 4232185029Spjd } 4233185029Spjd 4234185029Spjd switch (zc->zc_share.z_sharetype) { 4235185029Spjd case ZFS_SHARE_NFS: 4236185029Spjd case ZFS_UNSHARE_NFS: 4237185029Spjd if (error = 4238185029Spjd znfsexport_fs((void *) 4239185029Spjd (uintptr_t)zc->zc_share.z_exportdata)) 4240185029Spjd return (error); 4241185029Spjd break; 4242185029Spjd case ZFS_SHARE_SMB: 4243185029Spjd case ZFS_UNSHARE_SMB: 4244185029Spjd if (error = zsmbexport_fs((void *) 4245185029Spjd (uintptr_t)zc->zc_share.z_exportdata, 4246185029Spjd zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 4247209962Smm B_TRUE: B_FALSE)) { 4248185029Spjd return (error); 4249185029Spjd } 4250185029Spjd break; 4251185029Spjd } 4252185029Spjd 4253185029Spjd opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 4254185029Spjd zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 4255185029Spjd SHAREFS_ADD : SHAREFS_REMOVE; 4256185029Spjd 4257185029Spjd /* 4258185029Spjd * Add or remove share from sharetab 4259185029Spjd */ 4260185029Spjd error = zshare_fs(opcode, 4261185029Spjd (void *)(uintptr_t)zc->zc_share.z_sharedata, 4262185029Spjd zc->zc_share.z_sharemax); 4263185029Spjd 4264185029Spjd return (error); 4265219089Spjd 4266219089Spjd#else /* !sun */ 4267185029Spjd return (ENOSYS); 4268219089Spjd#endif /* !sun */ 4269185029Spjd} 4270185029Spjd 4271209962Smmace_t full_access[] = { 4272209962Smm {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 4273209962Smm}; 4274209962Smm 4275219089Spjd/* 4276219089Spjd * inputs: 4277219089Spjd * zc_name name of containing filesystem 4278219089Spjd * zc_obj object # beyond which we want next in-use object # 4279219089Spjd * 4280219089Spjd * outputs: 4281219089Spjd * zc_obj next in-use object # 4282219089Spjd */ 4283219089Spjdstatic int 4284219089Spjdzfs_ioc_next_obj(zfs_cmd_t *zc) 4285219089Spjd{ 4286219089Spjd objset_t *os = NULL; 4287219089Spjd int error; 4288219089Spjd 4289219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &os); 4290219089Spjd if (error) 4291219089Spjd return (error); 4292219089Spjd 4293219089Spjd error = dmu_object_next(os, &zc->zc_obj, B_FALSE, 4294219089Spjd os->os_dsl_dataset->ds_phys->ds_prev_snap_txg); 4295219089Spjd 4296219089Spjd dmu_objset_rele(os, FTAG); 4297219089Spjd return (error); 4298219089Spjd} 4299219089Spjd 4300219089Spjd/* 4301219089Spjd * inputs: 4302219089Spjd * zc_name name of filesystem 4303219089Spjd * zc_value prefix name for snapshot 4304219089Spjd * zc_cleanup_fd cleanup-on-exit file descriptor for calling process 4305219089Spjd * 4306219089Spjd * outputs: 4307219089Spjd */ 4308219089Spjdstatic int 4309219089Spjdzfs_ioc_tmp_snapshot(zfs_cmd_t *zc) 4310219089Spjd{ 4311219089Spjd char *snap_name; 4312219089Spjd int error; 4313219089Spjd 4314219089Spjd snap_name = kmem_asprintf("%s-%016llx", zc->zc_value, 4315219089Spjd (u_longlong_t)ddi_get_lbolt64()); 4316219089Spjd 4317219089Spjd if (strlen(snap_name) >= MAXNAMELEN) { 4318219089Spjd strfree(snap_name); 4319219089Spjd return (E2BIG); 4320219089Spjd } 4321219089Spjd 4322219089Spjd error = dmu_objset_snapshot(zc->zc_name, snap_name, snap_name, 4323219089Spjd NULL, B_FALSE, B_TRUE, zc->zc_cleanup_fd); 4324219089Spjd if (error != 0) { 4325219089Spjd strfree(snap_name); 4326219089Spjd return (error); 4327219089Spjd } 4328219089Spjd 4329219089Spjd (void) strcpy(zc->zc_value, snap_name); 4330219089Spjd strfree(snap_name); 4331219089Spjd return (0); 4332219089Spjd} 4333219089Spjd 4334219089Spjd/* 4335219089Spjd * inputs: 4336219089Spjd * zc_name name of "to" snapshot 4337219089Spjd * zc_value name of "from" snapshot 4338219089Spjd * zc_cookie file descriptor to write diff data on 4339219089Spjd * 4340219089Spjd * outputs: 4341219089Spjd * dmu_diff_record_t's to the file descriptor 4342219089Spjd */ 4343219089Spjdstatic int 4344219089Spjdzfs_ioc_diff(zfs_cmd_t *zc) 4345219089Spjd{ 4346219089Spjd objset_t *fromsnap; 4347219089Spjd objset_t *tosnap; 4348219089Spjd file_t *fp; 4349219089Spjd offset_t off; 4350219089Spjd int error; 4351219089Spjd 4352219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &tosnap); 4353219089Spjd if (error) 4354219089Spjd return (error); 4355219089Spjd 4356219089Spjd error = dmu_objset_hold(zc->zc_value, FTAG, &fromsnap); 4357219089Spjd if (error) { 4358219089Spjd dmu_objset_rele(tosnap, FTAG); 4359219089Spjd return (error); 4360219089Spjd } 4361219089Spjd 4362219089Spjd fp = getf(zc->zc_cookie); 4363219089Spjd if (fp == NULL) { 4364219089Spjd dmu_objset_rele(fromsnap, FTAG); 4365219089Spjd dmu_objset_rele(tosnap, FTAG); 4366219089Spjd return (EBADF); 4367219089Spjd } 4368219089Spjd 4369219089Spjd off = fp->f_offset; 4370219089Spjd 4371219089Spjd error = dmu_diff(tosnap, fromsnap, fp, &off); 4372219089Spjd 4373219089Spjd if (off >= 0 && off <= MAXOFFSET_T) 4374219089Spjd fp->f_offset = off; 4375219089Spjd releasef(zc->zc_cookie); 4376219089Spjd 4377219089Spjd dmu_objset_rele(fromsnap, FTAG); 4378219089Spjd dmu_objset_rele(tosnap, FTAG); 4379219089Spjd return (error); 4380219089Spjd} 4381219089Spjd 4382209962Smm#ifdef sun 4383185029Spjd/* 4384209962Smm * Remove all ACL files in shares dir 4385209962Smm */ 4386209962Smmstatic int 4387209962Smmzfs_smb_acl_purge(znode_t *dzp) 4388209962Smm{ 4389209962Smm zap_cursor_t zc; 4390209962Smm zap_attribute_t zap; 4391209962Smm zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 4392209962Smm int error; 4393209962Smm 4394209962Smm for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 4395209962Smm (error = zap_cursor_retrieve(&zc, &zap)) == 0; 4396209962Smm zap_cursor_advance(&zc)) { 4397209962Smm if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 4398209962Smm NULL, 0)) != 0) 4399209962Smm break; 4400209962Smm } 4401209962Smm zap_cursor_fini(&zc); 4402209962Smm return (error); 4403209962Smm} 4404209962Smm#endif /* sun */ 4405209962Smm 4406209962Smmstatic int 4407209962Smmzfs_ioc_smb_acl(zfs_cmd_t *zc) 4408209962Smm{ 4409209962Smm#ifdef sun 4410209962Smm vnode_t *vp; 4411209962Smm znode_t *dzp; 4412209962Smm vnode_t *resourcevp = NULL; 4413209962Smm znode_t *sharedir; 4414209962Smm zfsvfs_t *zfsvfs; 4415209962Smm nvlist_t *nvlist; 4416209962Smm char *src, *target; 4417209962Smm vattr_t vattr; 4418209962Smm vsecattr_t vsec; 4419209962Smm int error = 0; 4420209962Smm 4421209962Smm if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 4422209962Smm NO_FOLLOW, NULL, &vp)) != 0) 4423209962Smm return (error); 4424209962Smm 4425209962Smm /* Now make sure mntpnt and dataset are ZFS */ 4426209962Smm 4427219089Spjd if (strcmp(vp->v_vfsp->mnt_stat.f_fstypename, "zfs") != 0 || 4428209962Smm (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 4429209962Smm zc->zc_name) != 0)) { 4430209962Smm VN_RELE(vp); 4431209962Smm return (EINVAL); 4432209962Smm } 4433209962Smm 4434209962Smm dzp = VTOZ(vp); 4435209962Smm zfsvfs = dzp->z_zfsvfs; 4436209962Smm ZFS_ENTER(zfsvfs); 4437209962Smm 4438209962Smm /* 4439209962Smm * Create share dir if its missing. 4440209962Smm */ 4441209962Smm mutex_enter(&zfsvfs->z_lock); 4442209962Smm if (zfsvfs->z_shares_dir == 0) { 4443209962Smm dmu_tx_t *tx; 4444209962Smm 4445209962Smm tx = dmu_tx_create(zfsvfs->z_os); 4446209962Smm dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 4447209962Smm ZFS_SHARES_DIR); 4448209962Smm dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 4449209962Smm error = dmu_tx_assign(tx, TXG_WAIT); 4450209962Smm if (error) { 4451209962Smm dmu_tx_abort(tx); 4452209962Smm } else { 4453209962Smm error = zfs_create_share_dir(zfsvfs, tx); 4454209962Smm dmu_tx_commit(tx); 4455209962Smm } 4456209962Smm if (error) { 4457209962Smm mutex_exit(&zfsvfs->z_lock); 4458209962Smm VN_RELE(vp); 4459209962Smm ZFS_EXIT(zfsvfs); 4460209962Smm return (error); 4461209962Smm } 4462209962Smm } 4463209962Smm mutex_exit(&zfsvfs->z_lock); 4464209962Smm 4465209962Smm ASSERT(zfsvfs->z_shares_dir); 4466209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 4467209962Smm VN_RELE(vp); 4468209962Smm ZFS_EXIT(zfsvfs); 4469209962Smm return (error); 4470209962Smm } 4471209962Smm 4472209962Smm switch (zc->zc_cookie) { 4473209962Smm case ZFS_SMB_ACL_ADD: 4474209962Smm vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 4475209962Smm vattr.va_type = VREG; 4476209962Smm vattr.va_mode = S_IFREG|0777; 4477209962Smm vattr.va_uid = 0; 4478209962Smm vattr.va_gid = 0; 4479209962Smm 4480209962Smm vsec.vsa_mask = VSA_ACE; 4481209962Smm vsec.vsa_aclentp = &full_access; 4482209962Smm vsec.vsa_aclentsz = sizeof (full_access); 4483209962Smm vsec.vsa_aclcnt = 1; 4484209962Smm 4485209962Smm error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 4486209962Smm &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 4487209962Smm if (resourcevp) 4488209962Smm VN_RELE(resourcevp); 4489209962Smm break; 4490209962Smm 4491209962Smm case ZFS_SMB_ACL_REMOVE: 4492209962Smm error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 4493209962Smm NULL, 0); 4494209962Smm break; 4495209962Smm 4496209962Smm case ZFS_SMB_ACL_RENAME: 4497209962Smm if ((error = get_nvlist(zc->zc_nvlist_src, 4498219089Spjd zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { 4499209962Smm VN_RELE(vp); 4500209962Smm ZFS_EXIT(zfsvfs); 4501209962Smm return (error); 4502209962Smm } 4503209962Smm if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 4504209962Smm nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 4505209962Smm &target)) { 4506209962Smm VN_RELE(vp); 4507209962Smm VN_RELE(ZTOV(sharedir)); 4508209962Smm ZFS_EXIT(zfsvfs); 4509219089Spjd nvlist_free(nvlist); 4510209962Smm return (error); 4511209962Smm } 4512209962Smm error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 4513209962Smm kcred, NULL, 0); 4514209962Smm nvlist_free(nvlist); 4515209962Smm break; 4516209962Smm 4517209962Smm case ZFS_SMB_ACL_PURGE: 4518209962Smm error = zfs_smb_acl_purge(sharedir); 4519209962Smm break; 4520209962Smm 4521209962Smm default: 4522209962Smm error = EINVAL; 4523209962Smm break; 4524209962Smm } 4525209962Smm 4526209962Smm VN_RELE(vp); 4527209962Smm VN_RELE(ZTOV(sharedir)); 4528209962Smm 4529209962Smm ZFS_EXIT(zfsvfs); 4530209962Smm 4531209962Smm return (error); 4532209962Smm#else /* !sun */ 4533209962Smm return (EOPNOTSUPP); 4534209962Smm#endif /* !sun */ 4535209962Smm} 4536209962Smm 4537209962Smm/* 4538219089Spjd * inputs: 4539219089Spjd * zc_name name of filesystem 4540219089Spjd * zc_value short name of snap 4541219089Spjd * zc_string user-supplied tag for this hold 4542219089Spjd * zc_cookie recursive flag 4543219089Spjd * zc_temphold set if hold is temporary 4544219089Spjd * zc_cleanup_fd cleanup-on-exit file descriptor for calling process 4545219089Spjd * zc_sendobj if non-zero, the objid for zc_name@zc_value 4546219089Spjd * zc_createtxg if zc_sendobj is non-zero, snap must have zc_createtxg 4547219089Spjd * 4548219089Spjd * outputs: none 4549219089Spjd */ 4550219089Spjdstatic int 4551219089Spjdzfs_ioc_hold(zfs_cmd_t *zc) 4552219089Spjd{ 4553219089Spjd boolean_t recursive = zc->zc_cookie; 4554219089Spjd spa_t *spa; 4555219089Spjd dsl_pool_t *dp; 4556219089Spjd dsl_dataset_t *ds; 4557219089Spjd int error; 4558219089Spjd minor_t minor = 0; 4559219089Spjd 4560219089Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 4561219089Spjd return (EINVAL); 4562219089Spjd 4563219089Spjd if (zc->zc_sendobj == 0) { 4564219089Spjd return (dsl_dataset_user_hold(zc->zc_name, zc->zc_value, 4565219089Spjd zc->zc_string, recursive, zc->zc_temphold, 4566219089Spjd zc->zc_cleanup_fd)); 4567219089Spjd } 4568219089Spjd 4569219089Spjd if (recursive) 4570219089Spjd return (EINVAL); 4571219089Spjd 4572219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 4573219089Spjd if (error) 4574219089Spjd return (error); 4575219089Spjd 4576219089Spjd dp = spa_get_dsl(spa); 4577219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 4578219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 4579219089Spjd rw_exit(&dp->dp_config_rwlock); 4580219089Spjd spa_close(spa, FTAG); 4581219089Spjd if (error) 4582219089Spjd return (error); 4583219089Spjd 4584219089Spjd /* 4585219089Spjd * Until we have a hold on this snapshot, it's possible that 4586219089Spjd * zc_sendobj could've been destroyed and reused as part 4587219089Spjd * of a later txg. Make sure we're looking at the right object. 4588219089Spjd */ 4589219089Spjd if (zc->zc_createtxg != ds->ds_phys->ds_creation_txg) { 4590219089Spjd dsl_dataset_rele(ds, FTAG); 4591219089Spjd return (ENOENT); 4592219089Spjd } 4593219089Spjd 4594219089Spjd if (zc->zc_cleanup_fd != -1 && zc->zc_temphold) { 4595219089Spjd error = zfs_onexit_fd_hold(zc->zc_cleanup_fd, &minor); 4596219089Spjd if (error) { 4597219089Spjd dsl_dataset_rele(ds, FTAG); 4598219089Spjd return (error); 4599219089Spjd } 4600219089Spjd } 4601219089Spjd 4602219089Spjd error = dsl_dataset_user_hold_for_send(ds, zc->zc_string, 4603219089Spjd zc->zc_temphold); 4604219089Spjd if (minor != 0) { 4605219089Spjd if (error == 0) { 4606219089Spjd dsl_register_onexit_hold_cleanup(ds, zc->zc_string, 4607219089Spjd minor); 4608219089Spjd } 4609219089Spjd zfs_onexit_fd_rele(zc->zc_cleanup_fd); 4610219089Spjd } 4611219089Spjd dsl_dataset_rele(ds, FTAG); 4612219089Spjd 4613219089Spjd return (error); 4614219089Spjd} 4615219089Spjd 4616219089Spjd/* 4617219089Spjd * inputs: 4618219089Spjd * zc_name name of dataset from which we're releasing a user hold 4619219089Spjd * zc_value short name of snap 4620219089Spjd * zc_string user-supplied tag for this hold 4621219089Spjd * zc_cookie recursive flag 4622219089Spjd * 4623219089Spjd * outputs: none 4624219089Spjd */ 4625219089Spjdstatic int 4626219089Spjdzfs_ioc_release(zfs_cmd_t *zc) 4627219089Spjd{ 4628219089Spjd boolean_t recursive = zc->zc_cookie; 4629219089Spjd 4630219089Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 4631219089Spjd return (EINVAL); 4632219089Spjd 4633219089Spjd return (dsl_dataset_user_release(zc->zc_name, zc->zc_value, 4634219089Spjd zc->zc_string, recursive)); 4635219089Spjd} 4636219089Spjd 4637219089Spjd/* 4638219089Spjd * inputs: 4639219089Spjd * zc_name name of filesystem 4640219089Spjd * 4641219089Spjd * outputs: 4642219089Spjd * zc_nvlist_src{_size} nvlist of snapshot holds 4643219089Spjd */ 4644219089Spjdstatic int 4645219089Spjdzfs_ioc_get_holds(zfs_cmd_t *zc) 4646219089Spjd{ 4647219089Spjd nvlist_t *nvp; 4648219089Spjd int error; 4649219089Spjd 4650219089Spjd if ((error = dsl_dataset_get_holds(zc->zc_name, &nvp)) == 0) { 4651219089Spjd error = put_nvlist(zc, nvp); 4652219089Spjd nvlist_free(nvp); 4653219089Spjd } 4654219089Spjd 4655219089Spjd return (error); 4656219089Spjd} 4657219089Spjd 4658219089Spjd/* 4659185029Spjd * pool create, destroy, and export don't log the history as part of 4660185029Spjd * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 4661185029Spjd * do the logging of those commands. 4662185029Spjd */ 4663185029Spjdstatic int 4664168404Spjdzfs_ioc_jail(zfs_cmd_t *zc) 4665168404Spjd{ 4666168404Spjd 4667185029Spjd return (zone_dataset_attach(curthread->td_ucred, zc->zc_name, 4668185029Spjd (int)zc->zc_jailid)); 4669168404Spjd} 4670168404Spjd 4671168404Spjdstatic int 4672168404Spjdzfs_ioc_unjail(zfs_cmd_t *zc) 4673168404Spjd{ 4674168404Spjd 4675185029Spjd return (zone_dataset_detach(curthread->td_ucred, zc->zc_name, 4676185029Spjd (int)zc->zc_jailid)); 4677168404Spjd} 4678168404Spjd 4679168404Spjdstatic zfs_ioc_vec_t zfs_ioc_vec[] = { 4680209962Smm { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE, 4681209962Smm B_FALSE }, 4682209962Smm { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE, 4683209962Smm B_FALSE }, 4684209962Smm { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4685209962Smm B_FALSE }, 4686209962Smm { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE, 4687209962Smm B_FALSE }, 4688209962Smm { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE, 4689209962Smm B_FALSE }, 4690209962Smm { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE, 4691209962Smm B_FALSE }, 4692209962Smm { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE, 4693209962Smm B_FALSE }, 4694219089Spjd { zfs_ioc_pool_scan, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4695209962Smm B_TRUE }, 4696209962Smm { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, 4697209962Smm B_FALSE }, 4698209962Smm { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4699209962Smm B_TRUE }, 4700209962Smm { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE, 4701209962Smm B_FALSE }, 4702209962Smm { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4703209962Smm B_TRUE }, 4704209962Smm { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4705209962Smm B_TRUE }, 4706209962Smm { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4707209962Smm B_FALSE }, 4708209962Smm { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4709209962Smm B_TRUE }, 4710209962Smm { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4711209962Smm B_TRUE }, 4712209962Smm { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE, 4713209962Smm B_TRUE }, 4714219089Spjd { zfs_ioc_vdev_setfru, zfs_secpolicy_config, POOL_NAME, B_FALSE, 4715219089Spjd B_TRUE }, 4716209962Smm { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4717209962Smm B_TRUE }, 4718209962Smm { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4719209962Smm B_FALSE }, 4720209962Smm { zfs_ioc_dataset_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4721209962Smm B_TRUE }, 4722209962Smm { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4723209962Smm B_TRUE }, 4724209962Smm { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, B_TRUE }, 4725209962Smm { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, B_TRUE }, 4726209962Smm { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 4727209962Smm B_TRUE}, 4728209962Smm { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE, 4729209962Smm B_TRUE }, 4730209962Smm { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE, B_TRUE }, 4731209962Smm { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE, B_TRUE }, 4732209962Smm { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE, B_FALSE }, 4733209962Smm { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 4734209962Smm B_FALSE }, 4735209962Smm { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 4736209962Smm B_FALSE }, 4737209962Smm { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE, 4738209962Smm B_FALSE }, 4739209962Smm { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE, 4740209962Smm B_FALSE }, 4741209962Smm { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE, B_FALSE }, 4742209962Smm { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE, 4743209962Smm B_TRUE }, 4744219089Spjd { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, DATASET_NAME, 4745219089Spjd B_TRUE, B_TRUE }, 4746209962Smm { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE, 4747209962Smm B_TRUE }, 4748219089Spjd { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_diff, POOL_NAME, B_FALSE, 4749209962Smm B_FALSE }, 4750219089Spjd { zfs_ioc_obj_to_path, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, 4751219089Spjd B_TRUE }, 4752209962Smm { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4753209962Smm B_TRUE }, 4754209962Smm { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE, 4755209962Smm B_FALSE }, 4756209962Smm { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE, 4757209962Smm B_TRUE }, 4758209962Smm { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4759209962Smm B_FALSE }, 4760209962Smm { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE, B_FALSE }, 4761209962Smm { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE, 4762209962Smm B_TRUE }, 4763209962Smm { zfs_ioc_smb_acl, zfs_secpolicy_smb_acl, DATASET_NAME, B_FALSE, 4764209962Smm B_FALSE }, 4765209962Smm { zfs_ioc_userspace_one, zfs_secpolicy_userspace_one, 4766209962Smm DATASET_NAME, B_FALSE, B_FALSE }, 4767209962Smm { zfs_ioc_userspace_many, zfs_secpolicy_userspace_many, 4768209962Smm DATASET_NAME, B_FALSE, B_FALSE }, 4769209962Smm { zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 4770209962Smm DATASET_NAME, B_FALSE, B_TRUE }, 4771219089Spjd { zfs_ioc_hold, zfs_secpolicy_hold, DATASET_NAME, B_TRUE, B_TRUE }, 4772219089Spjd { zfs_ioc_release, zfs_secpolicy_release, DATASET_NAME, B_TRUE, 4773219089Spjd B_TRUE }, 4774219089Spjd { zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4775219089Spjd B_TRUE }, 4776219089Spjd { zfs_ioc_objset_recvd_props, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4777219089Spjd B_FALSE }, 4778219089Spjd { zfs_ioc_vdev_split, zfs_secpolicy_config, POOL_NAME, B_TRUE, 4779219089Spjd B_TRUE }, 4780219089Spjd { zfs_ioc_next_obj, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 4781219089Spjd B_FALSE }, 4782219089Spjd { zfs_ioc_diff, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, B_FALSE }, 4783219089Spjd { zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot, DATASET_NAME, 4784219089Spjd B_FALSE, B_FALSE }, 4785219089Spjd { zfs_ioc_obj_to_stats, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, 4786219089Spjd B_TRUE }, 4787219089Spjd { zfs_ioc_jail, zfs_secpolicy_config, DATASET_NAME, B_TRUE, B_FALSE }, 4788219089Spjd { zfs_ioc_unjail, zfs_secpolicy_config, DATASET_NAME, B_TRUE, B_FALSE } 4789168404Spjd}; 4790168404Spjd 4791209962Smmint 4792209962Smmpool_status_check(const char *name, zfs_ioc_namecheck_t type) 4793209962Smm{ 4794209962Smm spa_t *spa; 4795209962Smm int error; 4796209962Smm 4797209962Smm ASSERT(type == POOL_NAME || type == DATASET_NAME); 4798209962Smm 4799209962Smm error = spa_open(name, &spa, FTAG); 4800209962Smm if (error == 0) { 4801209962Smm if (spa_suspended(spa)) 4802209962Smm error = EAGAIN; 4803209962Smm spa_close(spa, FTAG); 4804209962Smm } 4805209962Smm return (error); 4806209962Smm} 4807209962Smm 4808219089Spjd/* 4809219089Spjd * Find a free minor number. 4810219089Spjd */ 4811219089Spjdminor_t 4812219089Spjdzfsdev_minor_alloc(void) 4813219089Spjd{ 4814219089Spjd static minor_t last_minor; 4815219089Spjd minor_t m; 4816219089Spjd 4817224791Spjd ASSERT(MUTEX_HELD(&spa_namespace_lock)); 4818219089Spjd 4819219089Spjd for (m = last_minor + 1; m != last_minor; m++) { 4820219089Spjd if (m > ZFSDEV_MAX_MINOR) 4821219089Spjd m = 1; 4822219089Spjd if (ddi_get_soft_state(zfsdev_state, m) == NULL) { 4823219089Spjd last_minor = m; 4824219089Spjd return (m); 4825219089Spjd } 4826219089Spjd } 4827219089Spjd 4828219089Spjd return (0); 4829219089Spjd} 4830219089Spjd 4831168404Spjdstatic int 4832219089Spjdzfs_ctldev_init(struct cdev *devp) 4833219089Spjd{ 4834219089Spjd minor_t minor; 4835219089Spjd zfs_soft_state_t *zs; 4836219089Spjd 4837224791Spjd ASSERT(MUTEX_HELD(&spa_namespace_lock)); 4838219089Spjd 4839219089Spjd minor = zfsdev_minor_alloc(); 4840219089Spjd if (minor == 0) 4841219089Spjd return (ENXIO); 4842219089Spjd 4843219089Spjd if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) 4844219089Spjd return (EAGAIN); 4845219089Spjd 4846219089Spjd devfs_set_cdevpriv((void *)(uintptr_t)minor, zfsdev_close); 4847219089Spjd 4848219089Spjd zs = ddi_get_soft_state(zfsdev_state, minor); 4849219089Spjd zs->zss_type = ZSST_CTLDEV; 4850219089Spjd zfs_onexit_init((zfs_onexit_t **)&zs->zss_data); 4851219089Spjd 4852219089Spjd return (0); 4853219089Spjd} 4854219089Spjd 4855219089Spjdstatic void 4856219089Spjdzfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor) 4857219089Spjd{ 4858224791Spjd ASSERT(MUTEX_HELD(&spa_namespace_lock)); 4859219089Spjd 4860219089Spjd zfs_onexit_destroy(zo); 4861219089Spjd ddi_soft_state_free(zfsdev_state, minor); 4862219089Spjd} 4863219089Spjd 4864219089Spjdvoid * 4865219089Spjdzfsdev_get_soft_state(minor_t minor, enum zfs_soft_state_type which) 4866219089Spjd{ 4867219089Spjd zfs_soft_state_t *zp; 4868219089Spjd 4869219089Spjd zp = ddi_get_soft_state(zfsdev_state, minor); 4870219089Spjd if (zp == NULL || zp->zss_type != which) 4871219089Spjd return (NULL); 4872219089Spjd 4873219089Spjd return (zp->zss_data); 4874219089Spjd} 4875219089Spjd 4876219089Spjdstatic int 4877219089Spjdzfsdev_open(struct cdev *devp, int flag, int mode, struct thread *td) 4878219089Spjd{ 4879219089Spjd int error = 0; 4880219089Spjd 4881219089Spjd#ifdef sun 4882219089Spjd if (getminor(*devp) != 0) 4883219089Spjd return (zvol_open(devp, flag, otyp, cr)); 4884219089Spjd#endif 4885219089Spjd 4886219089Spjd /* This is the control device. Allocate a new minor if requested. */ 4887219089Spjd if (flag & FEXCL) { 4888224791Spjd mutex_enter(&spa_namespace_lock); 4889219089Spjd error = zfs_ctldev_init(devp); 4890224791Spjd mutex_exit(&spa_namespace_lock); 4891219089Spjd } 4892219089Spjd 4893219089Spjd return (error); 4894219089Spjd} 4895219089Spjd 4896219089Spjdstatic void 4897219089Spjdzfsdev_close(void *data) 4898219089Spjd{ 4899219089Spjd zfs_onexit_t *zo; 4900219089Spjd minor_t minor = (minor_t)(uintptr_t)data; 4901219089Spjd 4902219089Spjd if (minor == 0) 4903219089Spjd return; 4904219089Spjd 4905224791Spjd mutex_enter(&spa_namespace_lock); 4906219089Spjd zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); 4907219089Spjd if (zo == NULL) { 4908224791Spjd mutex_exit(&spa_namespace_lock); 4909219089Spjd return; 4910219089Spjd } 4911219089Spjd zfs_ctldev_destroy(zo, minor); 4912224791Spjd mutex_exit(&spa_namespace_lock); 4913219089Spjd} 4914219089Spjd 4915219089Spjdstatic int 4916168404Spjdzfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 4917168404Spjd struct thread *td) 4918168404Spjd{ 4919219089Spjd zfs_cmd_t *zc; 4920168404Spjd uint_t vec; 4921219089Spjd int cflag, error, len; 4922168404Spjd 4923219089Spjd cflag = ZFS_CMD_COMPAT_NONE; 4924219089Spjd len = IOCPARM_LEN(cmd); 4925219089Spjd 4926214854Sdelphij /* 4927214854Sdelphij * Check if we have sufficient kernel memory allocated 4928214854Sdelphij * for the zfs_cmd_t request. Bail out if not so we 4929214854Sdelphij * will not access undefined memory region. 4930214854Sdelphij */ 4931219089Spjd if (len < sizeof(zfs_cmd_t)) 4932219089Spjd if (len == sizeof(zfs_cmd_v15_t)) { 4933219089Spjd cflag = ZFS_CMD_COMPAT_V15; 4934219089Spjd vec = zfs_ioctl_v15_to_v28[ZFS_IOC(cmd)]; 4935219089Spjd } else 4936219089Spjd return (EINVAL); 4937219089Spjd else 4938219089Spjd vec = ZFS_IOC(cmd); 4939214854Sdelphij 4940219089Spjd if (cflag != ZFS_CMD_COMPAT_NONE) { 4941219089Spjd if (vec == ZFS_IOC_COMPAT_PASS) 4942219089Spjd return (0); 4943219089Spjd else if (vec == ZFS_IOC_COMPAT_FAIL) 4944219089Spjd return (ENOTSUP); 4945219089Spjd } 4946168404Spjd 4947168404Spjd if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 4948168404Spjd return (EINVAL); 4949168404Spjd 4950219089Spjd if (cflag != ZFS_CMD_COMPAT_NONE) { 4951219089Spjd zc = kmem_zalloc(sizeof(zfs_cmd_t), KM_SLEEP); 4952219089Spjd bzero(zc, sizeof(zfs_cmd_t)); 4953219089Spjd zfs_cmd_compat_get(zc, addr, cflag); 4954219089Spjd zfs_ioctl_compat_pre(zc, &vec, cflag); 4955219089Spjd } else { 4956219089Spjd zc = (void *)addr; 4957219089Spjd } 4958219089Spjd 4959185029Spjd error = zfs_ioc_vec[vec].zvec_secpolicy(zc, td->td_ucred); 4960168404Spjd 4961168404Spjd /* 4962168404Spjd * Ensure that all pool/dataset names are valid before we pass down to 4963168404Spjd * the lower layers. 4964168404Spjd */ 4965168404Spjd if (error == 0) { 4966168404Spjd zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 4967219089Spjd zc->zc_iflags = flag & FKIOCTL; 4968168404Spjd switch (zfs_ioc_vec[vec].zvec_namecheck) { 4969185029Spjd case POOL_NAME: 4970168404Spjd if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 4971168404Spjd error = EINVAL; 4972209962Smm if (zfs_ioc_vec[vec].zvec_pool_check) 4973209962Smm error = pool_status_check(zc->zc_name, 4974209962Smm zfs_ioc_vec[vec].zvec_namecheck); 4975168404Spjd break; 4976168404Spjd 4977185029Spjd case DATASET_NAME: 4978168404Spjd if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 4979168404Spjd error = EINVAL; 4980209962Smm if (zfs_ioc_vec[vec].zvec_pool_check) 4981209962Smm error = pool_status_check(zc->zc_name, 4982209962Smm zfs_ioc_vec[vec].zvec_namecheck); 4983168404Spjd break; 4984168404Spjd 4985185029Spjd case NO_NAME: 4986168404Spjd break; 4987168404Spjd } 4988168404Spjd } 4989168404Spjd 4990168404Spjd if (error == 0) 4991168404Spjd error = zfs_ioc_vec[vec].zvec_func(zc); 4992168404Spjd 4993196985Spjd if (error == 0) { 4994209962Smm if (zfs_ioc_vec[vec].zvec_his_log) 4995196985Spjd zfs_log_history(zc); 4996196985Spjd } 4997185029Spjd 4998219089Spjd if (cflag != ZFS_CMD_COMPAT_NONE) { 4999219089Spjd zfs_ioctl_compat_post(zc, ZFS_IOC(cmd), cflag); 5000219089Spjd zfs_cmd_compat_put(zc, addr, cflag); 5001219089Spjd kmem_free(zc, sizeof(zfs_cmd_t)); 5002219089Spjd } 5003219089Spjd 5004168404Spjd return (error); 5005168404Spjd} 5006168404Spjd 5007219089Spjd#ifdef sun 5008219089Spjdstatic int 5009219089Spjdzfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5010219089Spjd{ 5011219089Spjd if (cmd != DDI_ATTACH) 5012219089Spjd return (DDI_FAILURE); 5013219089Spjd 5014219089Spjd if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 5015219089Spjd DDI_PSEUDO, 0) == DDI_FAILURE) 5016219089Spjd return (DDI_FAILURE); 5017219089Spjd 5018219089Spjd zfs_dip = dip; 5019219089Spjd 5020219089Spjd ddi_report_dev(dip); 5021219089Spjd 5022219089Spjd return (DDI_SUCCESS); 5023219089Spjd} 5024219089Spjd 5025219089Spjdstatic int 5026219089Spjdzfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5027219089Spjd{ 5028219089Spjd if (spa_busy() || zfs_busy() || zvol_busy()) 5029219089Spjd return (DDI_FAILURE); 5030219089Spjd 5031219089Spjd if (cmd != DDI_DETACH) 5032219089Spjd return (DDI_FAILURE); 5033219089Spjd 5034219089Spjd zfs_dip = NULL; 5035219089Spjd 5036219089Spjd ddi_prop_remove_all(dip); 5037219089Spjd ddi_remove_minor_node(dip, NULL); 5038219089Spjd 5039219089Spjd return (DDI_SUCCESS); 5040219089Spjd} 5041219089Spjd 5042219089Spjd/*ARGSUSED*/ 5043219089Spjdstatic int 5044219089Spjdzfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 5045219089Spjd{ 5046219089Spjd switch (infocmd) { 5047219089Spjd case DDI_INFO_DEVT2DEVINFO: 5048219089Spjd *result = zfs_dip; 5049219089Spjd return (DDI_SUCCESS); 5050219089Spjd 5051219089Spjd case DDI_INFO_DEVT2INSTANCE: 5052219089Spjd *result = (void *)0; 5053219089Spjd return (DDI_SUCCESS); 5054219089Spjd } 5055219089Spjd 5056219089Spjd return (DDI_FAILURE); 5057219089Spjd} 5058219089Spjd#endif /* sun */ 5059219089Spjd 5060168404Spjd/* 5061168404Spjd * OK, so this is a little weird. 5062168404Spjd * 5063168404Spjd * /dev/zfs is the control node, i.e. minor 0. 5064168404Spjd * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 5065168404Spjd * 5066168404Spjd * /dev/zfs has basically nothing to do except serve up ioctls, 5067168404Spjd * so most of the standard driver entry points are in zvol.c. 5068168404Spjd */ 5069219089Spjd#ifdef sun 5070219089Spjdstatic struct cb_ops zfs_cb_ops = { 5071219089Spjd zfsdev_open, /* open */ 5072219089Spjd zfsdev_close, /* close */ 5073219089Spjd zvol_strategy, /* strategy */ 5074219089Spjd nodev, /* print */ 5075219089Spjd zvol_dump, /* dump */ 5076219089Spjd zvol_read, /* read */ 5077219089Spjd zvol_write, /* write */ 5078219089Spjd zfsdev_ioctl, /* ioctl */ 5079219089Spjd nodev, /* devmap */ 5080219089Spjd nodev, /* mmap */ 5081219089Spjd nodev, /* segmap */ 5082219089Spjd nochpoll, /* poll */ 5083219089Spjd ddi_prop_op, /* prop_op */ 5084219089Spjd NULL, /* streamtab */ 5085219089Spjd D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 5086219089Spjd CB_REV, /* version */ 5087219089Spjd nodev, /* async read */ 5088219089Spjd nodev, /* async write */ 5089219089Spjd}; 5090219089Spjd 5091219089Spjdstatic struct dev_ops zfs_dev_ops = { 5092219089Spjd DEVO_REV, /* version */ 5093219089Spjd 0, /* refcnt */ 5094219089Spjd zfs_info, /* info */ 5095219089Spjd nulldev, /* identify */ 5096219089Spjd nulldev, /* probe */ 5097219089Spjd zfs_attach, /* attach */ 5098219089Spjd zfs_detach, /* detach */ 5099219089Spjd nodev, /* reset */ 5100219089Spjd &zfs_cb_ops, /* driver operations */ 5101219089Spjd NULL, /* no bus operations */ 5102219089Spjd NULL, /* power */ 5103219089Spjd ddi_quiesce_not_needed, /* quiesce */ 5104219089Spjd}; 5105219089Spjd 5106219089Spjdstatic struct modldrv zfs_modldrv = { 5107219089Spjd &mod_driverops, 5108219089Spjd "ZFS storage pool", 5109219089Spjd &zfs_dev_ops 5110219089Spjd}; 5111219089Spjd 5112219089Spjdstatic struct modlinkage modlinkage = { 5113219089Spjd MODREV_1, 5114219089Spjd (void *)&zfs_modlfs, 5115219089Spjd (void *)&zfs_modldrv, 5116219089Spjd NULL 5117219089Spjd}; 5118219089Spjd#endif /* sun */ 5119219089Spjd 5120168404Spjdstatic struct cdevsw zfs_cdevsw = { 5121168404Spjd .d_version = D_VERSION, 5122219089Spjd .d_open = zfsdev_open, 5123168404Spjd .d_ioctl = zfsdev_ioctl, 5124168404Spjd .d_name = ZFS_DEV_NAME 5125168404Spjd}; 5126168404Spjd 5127168404Spjdstatic void 5128168404Spjdzfsdev_init(void) 5129168404Spjd{ 5130185029Spjd zfsdev = make_dev(&zfs_cdevsw, 0x0, UID_ROOT, GID_OPERATOR, 0666, 5131168404Spjd ZFS_DEV_NAME); 5132168404Spjd} 5133168404Spjd 5134168404Spjdstatic void 5135168404Spjdzfsdev_fini(void) 5136168404Spjd{ 5137168404Spjd if (zfsdev != NULL) 5138168404Spjd destroy_dev(zfsdev); 5139168404Spjd} 5140168404Spjd 5141169929Spjdstatic struct root_hold_token *zfs_root_token; 5142196458Spjdstruct proc *zfsproc; 5143168404Spjd 5144185029Spjduint_t zfs_fsyncer_key; 5145185029Spjdextern uint_t rrw_tsd_key; 5146185029Spjd 5147219089Spjd#ifdef sun 5148219089Spjdint 5149219089Spjd_init(void) 5150219089Spjd{ 5151219089Spjd int error; 5152219089Spjd 5153219089Spjd spa_init(FREAD | FWRITE); 5154219089Spjd zfs_init(); 5155219089Spjd zvol_init(); 5156219089Spjd 5157219089Spjd if ((error = mod_install(&modlinkage)) != 0) { 5158219089Spjd zvol_fini(); 5159219089Spjd zfs_fini(); 5160219089Spjd spa_fini(); 5161219089Spjd return (error); 5162219089Spjd } 5163219089Spjd 5164219089Spjd tsd_create(&zfs_fsyncer_key, NULL); 5165219089Spjd tsd_create(&rrw_tsd_key, NULL); 5166219089Spjd 5167219089Spjd error = ldi_ident_from_mod(&modlinkage, &zfs_li); 5168219089Spjd ASSERT(error == 0); 5169219089Spjd mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 5170219089Spjd 5171219089Spjd return (0); 5172219089Spjd} 5173219089Spjd 5174219089Spjdint 5175219089Spjd_fini(void) 5176219089Spjd{ 5177219089Spjd int error; 5178219089Spjd 5179219089Spjd if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 5180219089Spjd return (EBUSY); 5181219089Spjd 5182219089Spjd if ((error = mod_remove(&modlinkage)) != 0) 5183219089Spjd return (error); 5184219089Spjd 5185219089Spjd zvol_fini(); 5186219089Spjd zfs_fini(); 5187219089Spjd spa_fini(); 5188219089Spjd if (zfs_nfsshare_inited) 5189219089Spjd (void) ddi_modclose(nfs_mod); 5190219089Spjd if (zfs_smbshare_inited) 5191219089Spjd (void) ddi_modclose(smbsrv_mod); 5192219089Spjd if (zfs_nfsshare_inited || zfs_smbshare_inited) 5193219089Spjd (void) ddi_modclose(sharefs_mod); 5194219089Spjd 5195219089Spjd tsd_destroy(&zfs_fsyncer_key); 5196219089Spjd ldi_ident_release(zfs_li); 5197219089Spjd zfs_li = NULL; 5198219089Spjd mutex_destroy(&zfs_share_lock); 5199219089Spjd 5200219089Spjd return (error); 5201219089Spjd} 5202219089Spjd 5203219089Spjdint 5204219089Spjd_info(struct modinfo *modinfop) 5205219089Spjd{ 5206219089Spjd return (mod_info(&modlinkage, modinfop)); 5207219089Spjd} 5208219089Spjd#endif /* sun */ 5209219089Spjd 5210168404Spjdstatic int 5211168404Spjdzfs_modevent(module_t mod, int type, void *unused __unused) 5212168404Spjd{ 5213196291Spjd int error = 0; 5214168404Spjd 5215168404Spjd switch (type) { 5216168404Spjd case MOD_LOAD: 5217190878Sthompsa zfs_root_token = root_mount_hold("ZFS"); 5218196291Spjd 5219185029Spjd mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 5220196291Spjd 5221196291Spjd spa_init(FREAD | FWRITE); 5222196291Spjd zfs_init(); 5223196291Spjd zvol_init(); 5224196291Spjd 5225196291Spjd tsd_create(&zfs_fsyncer_key, NULL); 5226196291Spjd tsd_create(&rrw_tsd_key, NULL); 5227196291Spjd 5228196291Spjd printf("ZFS storage pool version " SPA_VERSION_STRING "\n"); 5229196291Spjd root_mount_rel(zfs_root_token); 5230196291Spjd 5231196291Spjd zfsdev_init(); 5232168404Spjd break; 5233168404Spjd case MOD_UNLOAD: 5234168775Spjd if (spa_busy() || zfs_busy() || zvol_busy() || 5235168404Spjd zio_injection_enabled) { 5236168404Spjd error = EBUSY; 5237168404Spjd break; 5238168404Spjd } 5239196291Spjd 5240196291Spjd zfsdev_fini(); 5241168404Spjd zvol_fini(); 5242168404Spjd zfs_fini(); 5243168404Spjd spa_fini(); 5244196291Spjd 5245185029Spjd tsd_destroy(&zfs_fsyncer_key); 5246185029Spjd tsd_destroy(&rrw_tsd_key); 5247196291Spjd 5248185029Spjd mutex_destroy(&zfs_share_lock); 5249168404Spjd break; 5250196291Spjd default: 5251196291Spjd error = EOPNOTSUPP; 5252196291Spjd break; 5253168404Spjd } 5254168404Spjd return (error); 5255168404Spjd} 5256168404Spjd 5257168404Spjdstatic moduledata_t zfs_mod = { 5258168404Spjd "zfsctrl", 5259168404Spjd zfs_modevent, 5260168404Spjd 0 5261168404Spjd}; 5262169929SpjdDECLARE_MODULE(zfsctrl, zfs_mod, SI_SUB_VFS, SI_ORDER_ANY); 5263179280SjbMODULE_DEPEND(zfsctrl, opensolaris, 1, 1, 1); 5264193128SkmacyMODULE_DEPEND(zfsctrl, krpc, 1, 1, 1); 5265