zfs_ioctl.c revision 247602
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 */ 21236884Smm 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24230438Spjd * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>. 25226707Spjd * All rights reserved. 26247540Smm * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 27228103Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 28236155Smm * Copyright (c) 2012 by Delphix. All rights reserved. 29235222Smm * Copyright (c) 2012, Joyent, Inc. All rights reserved. 30246586Sdelphij * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 31168404Spjd */ 32168404Spjd 33168962Spjd#include <sys/types.h> 34168404Spjd#include <sys/param.h> 35168404Spjd#include <sys/systm.h> 36168404Spjd#include <sys/conf.h> 37168404Spjd#include <sys/kernel.h> 38168404Spjd#include <sys/lock.h> 39168404Spjd#include <sys/malloc.h> 40168404Spjd#include <sys/mutex.h> 41168404Spjd#include <sys/proc.h> 42168404Spjd#include <sys/errno.h> 43168404Spjd#include <sys/uio.h> 44168962Spjd#include <sys/buf.h> 45168404Spjd#include <sys/file.h> 46168404Spjd#include <sys/kmem.h> 47168404Spjd#include <sys/conf.h> 48168404Spjd#include <sys/cmn_err.h> 49168404Spjd#include <sys/stat.h> 50168404Spjd#include <sys/zfs_ioctl.h> 51209962Smm#include <sys/zfs_vfsops.h> 52185029Spjd#include <sys/zfs_znode.h> 53168404Spjd#include <sys/zap.h> 54168404Spjd#include <sys/spa.h> 55168404Spjd#include <sys/spa_impl.h> 56168404Spjd#include <sys/vdev.h> 57168404Spjd#include <sys/dmu.h> 58168404Spjd#include <sys/dsl_dir.h> 59168404Spjd#include <sys/dsl_dataset.h> 60168404Spjd#include <sys/dsl_prop.h> 61185029Spjd#include <sys/dsl_deleg.h> 62185029Spjd#include <sys/dmu_objset.h> 63235222Smm#include <sys/dmu_impl.h> 64168962Spjd#include <sys/sunddi.h> 65168962Spjd#include <sys/policy.h> 66168962Spjd#include <sys/zone.h> 67168404Spjd#include <sys/nvpair.h> 68168404Spjd#include <sys/mount.h> 69168404Spjd#include <sys/taskqueue.h> 70168404Spjd#include <sys/sdt.h> 71168404Spjd#include <sys/varargs.h> 72168404Spjd#include <sys/fs/zfs.h> 73168404Spjd#include <sys/zfs_ctldir.h> 74185029Spjd#include <sys/zfs_dir.h> 75219089Spjd#include <sys/zfs_onexit.h> 76168404Spjd#include <sys/zvol.h> 77219089Spjd#include <sys/dsl_scan.h> 78185029Spjd#include <sys/dmu_objset.h> 79246586Sdelphij#include <sys/zfeature.h> 80168404Spjd 81168404Spjd#include "zfs_namecheck.h" 82168404Spjd#include "zfs_prop.h" 83185029Spjd#include "zfs_deleg.h" 84219089Spjd#include "zfs_comutil.h" 85219089Spjd#include "zfs_ioctl_compat.h" 86168404Spjd 87219089SpjdCTASSERT(sizeof(zfs_cmd_t) < IOCPARM_MAX); 88168404Spjd 89230397Spjdstatic int snapshot_list_prefetch; 90230397SpjdSYSCTL_DECL(_vfs_zfs); 91230397SpjdTUNABLE_INT("vfs.zfs.snapshot_list_prefetch", &snapshot_list_prefetch); 92230397SpjdSYSCTL_INT(_vfs_zfs, OID_AUTO, snapshot_list_prefetch, CTLFLAG_RW, 93230397Spjd &snapshot_list_prefetch, 0, "Prefetch data when listing snapshots"); 94230397Spjd 95168404Spjdstatic struct cdev *zfsdev; 96168404Spjd 97168404Spjdextern void zfs_init(void); 98168404Spjdextern void zfs_fini(void); 99168404Spjd 100168404Spjdtypedef int zfs_ioc_func_t(zfs_cmd_t *); 101185029Spjdtypedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); 102168404Spjd 103209962Smmtypedef enum { 104209962Smm NO_NAME, 105209962Smm POOL_NAME, 106209962Smm DATASET_NAME 107209962Smm} zfs_ioc_namecheck_t; 108209962Smm 109246688Smmtypedef enum { 110246688Smm POOL_CHECK_NONE = 1 << 0, 111246688Smm POOL_CHECK_SUSPENDED = 1 << 1, 112246688Smm POOL_CHECK_READONLY = 1 << 2 113246688Smm} zfs_ioc_poolcheck_t; 114246688Smm 115168404Spjdtypedef struct zfs_ioc_vec { 116168404Spjd zfs_ioc_func_t *zvec_func; 117168404Spjd zfs_secpolicy_func_t *zvec_secpolicy; 118209962Smm zfs_ioc_namecheck_t zvec_namecheck; 119185029Spjd boolean_t zvec_his_log; 120246688Smm zfs_ioc_poolcheck_t zvec_pool_check; 121168404Spjd} zfs_ioc_vec_t; 122168404Spjd 123209962Smm/* This array is indexed by zfs_userquota_prop_t */ 124209962Smmstatic const char *userquota_perms[] = { 125209962Smm ZFS_DELEG_PERM_USERUSED, 126209962Smm ZFS_DELEG_PERM_USERQUOTA, 127209962Smm ZFS_DELEG_PERM_GROUPUSED, 128209962Smm ZFS_DELEG_PERM_GROUPQUOTA, 129209962Smm}; 130209962Smm 131209962Smmstatic int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 132219089Spjdstatic int zfs_check_settable(const char *name, nvpair_t *property, 133219089Spjd cred_t *cr); 134219089Spjdstatic int zfs_check_clearable(char *dataset, nvlist_t *props, 135219089Spjd nvlist_t **errors); 136185029Spjdstatic int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 137185029Spjd boolean_t *); 138219089Spjdint zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t **); 139219089Spjd 140219089Spjdstatic void zfsdev_close(void *data); 141185029Spjd 142246586Sdelphijstatic int zfs_prop_activate_feature(dsl_pool_t *dp, zfeature_info_t *feature); 143246586Sdelphijstatic int zfs_prop_activate_feature_check(void *arg1, void *arg2, 144246586Sdelphij dmu_tx_t *tx); 145246586Sdelphijstatic void zfs_prop_activate_feature_sync(void *arg1, void *arg2, 146246586Sdelphij dmu_tx_t *tx); 147246586Sdelphij 148168404Spjd/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 149168404Spjdvoid 150168404Spjd__dprintf(const char *file, const char *func, int line, const char *fmt, ...) 151168404Spjd{ 152168404Spjd const char *newfile; 153219089Spjd char buf[512]; 154168404Spjd va_list adx; 155168404Spjd 156168404Spjd /* 157168404Spjd * Get rid of annoying "../common/" prefix to filename. 158168404Spjd */ 159168404Spjd newfile = strrchr(file, '/'); 160168404Spjd if (newfile != NULL) { 161168404Spjd newfile = newfile + 1; /* Get rid of leading / */ 162168404Spjd } else { 163168404Spjd newfile = file; 164168404Spjd } 165168404Spjd 166168404Spjd va_start(adx, fmt); 167168404Spjd (void) vsnprintf(buf, sizeof (buf), fmt, adx); 168168404Spjd va_end(adx); 169168404Spjd 170168404Spjd /* 171168404Spjd * To get this data, use the zfs-dprintf probe as so: 172168404Spjd * dtrace -q -n 'zfs-dprintf \ 173168404Spjd * /stringof(arg0) == "dbuf.c"/ \ 174168404Spjd * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 175168404Spjd * arg0 = file name 176168404Spjd * arg1 = function name 177168404Spjd * arg2 = line number 178168404Spjd * arg3 = message 179168404Spjd */ 180168404Spjd DTRACE_PROBE4(zfs__dprintf, 181168404Spjd char *, newfile, char *, func, int, line, char *, buf); 182168404Spjd} 183168404Spjd 184185029Spjdstatic void 185185029Spjdhistory_str_free(char *buf) 186185029Spjd{ 187185029Spjd kmem_free(buf, HIS_MAX_RECORD_LEN); 188185029Spjd} 189185029Spjd 190185029Spjdstatic char * 191185029Spjdhistory_str_get(zfs_cmd_t *zc) 192185029Spjd{ 193185029Spjd char *buf; 194185029Spjd 195185029Spjd if (zc->zc_history == 0) 196185029Spjd return (NULL); 197185029Spjd 198185029Spjd buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 199185029Spjd if (copyinstr((void *)(uintptr_t)zc->zc_history, 200185029Spjd buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 201185029Spjd history_str_free(buf); 202185029Spjd return (NULL); 203185029Spjd } 204185029Spjd 205185029Spjd buf[HIS_MAX_RECORD_LEN -1] = '\0'; 206185029Spjd 207185029Spjd return (buf); 208185029Spjd} 209185029Spjd 210168404Spjd/* 211185029Spjd * Check to see if the named dataset is currently defined as bootable 212185029Spjd */ 213185029Spjdstatic boolean_t 214185029Spjdzfs_is_bootfs(const char *name) 215185029Spjd{ 216219089Spjd objset_t *os; 217185029Spjd 218219089Spjd if (dmu_objset_hold(name, FTAG, &os) == 0) { 219219089Spjd boolean_t ret; 220219089Spjd ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os))); 221219089Spjd dmu_objset_rele(os, FTAG); 222219089Spjd return (ret); 223185029Spjd } 224219089Spjd return (B_FALSE); 225185029Spjd} 226185029Spjd 227185029Spjd/* 228185029Spjd * zfs_earlier_version 229185029Spjd * 230185029Spjd * Return non-zero if the spa version is less than requested version. 231185029Spjd */ 232185029Spjdstatic int 233185029Spjdzfs_earlier_version(const char *name, int version) 234185029Spjd{ 235185029Spjd spa_t *spa; 236185029Spjd 237185029Spjd if (spa_open(name, &spa, FTAG) == 0) { 238185029Spjd if (spa_version(spa) < version) { 239185029Spjd spa_close(spa, FTAG); 240185029Spjd return (1); 241185029Spjd } 242185029Spjd spa_close(spa, FTAG); 243185029Spjd } 244185029Spjd return (0); 245185029Spjd} 246185029Spjd 247185029Spjd/* 248185029Spjd * zpl_earlier_version 249185029Spjd * 250185029Spjd * Return TRUE if the ZPL version is less than requested version. 251185029Spjd */ 252185029Spjdstatic boolean_t 253185029Spjdzpl_earlier_version(const char *name, int version) 254185029Spjd{ 255185029Spjd objset_t *os; 256185029Spjd boolean_t rc = B_TRUE; 257185029Spjd 258219089Spjd if (dmu_objset_hold(name, FTAG, &os) == 0) { 259185029Spjd uint64_t zplversion; 260185029Spjd 261219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 262219089Spjd dmu_objset_rele(os, FTAG); 263219089Spjd return (B_TRUE); 264219089Spjd } 265219089Spjd /* XXX reading from non-owned objset */ 266185029Spjd if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 267185029Spjd rc = zplversion < version; 268219089Spjd dmu_objset_rele(os, FTAG); 269185029Spjd } 270185029Spjd return (rc); 271185029Spjd} 272185029Spjd 273185029Spjdstatic void 274185029Spjdzfs_log_history(zfs_cmd_t *zc) 275185029Spjd{ 276185029Spjd spa_t *spa; 277185029Spjd char *buf; 278185029Spjd 279185029Spjd if ((buf = history_str_get(zc)) == NULL) 280185029Spjd return; 281185029Spjd 282185029Spjd if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 283185029Spjd if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 284185029Spjd (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); 285185029Spjd spa_close(spa, FTAG); 286185029Spjd } 287185029Spjd history_str_free(buf); 288185029Spjd} 289185029Spjd 290185029Spjd/* 291168404Spjd * Policy for top-level read operations (list pools). Requires no privileges, 292168404Spjd * and can be used in the local zone, as there is no associated dataset. 293168404Spjd */ 294168404Spjd/* ARGSUSED */ 295168404Spjdstatic int 296185029Spjdzfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) 297168404Spjd{ 298168404Spjd return (0); 299168404Spjd} 300168404Spjd 301168404Spjd/* 302168404Spjd * Policy for dataset read operations (list children, get statistics). Requires 303168404Spjd * no privileges, but must be visible in the local zone. 304168404Spjd */ 305168404Spjd/* ARGSUSED */ 306168404Spjdstatic int 307185029Spjdzfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) 308168404Spjd{ 309185029Spjd if (INGLOBALZONE(curthread) || 310185029Spjd zone_dataset_visible(zc->zc_name, NULL)) 311168404Spjd return (0); 312168404Spjd 313168404Spjd return (ENOENT); 314168404Spjd} 315168404Spjd 316168404Spjdstatic int 317219089Spjdzfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr) 318168404Spjd{ 319168404Spjd int writable = 1; 320168404Spjd 321168404Spjd /* 322168404Spjd * The dataset must be visible by this zone -- check this first 323168404Spjd * so they don't see EPERM on something they shouldn't know about. 324168404Spjd */ 325185029Spjd if (!INGLOBALZONE(curthread) && 326168404Spjd !zone_dataset_visible(dataset, &writable)) 327168404Spjd return (ENOENT); 328168404Spjd 329185029Spjd if (INGLOBALZONE(curthread)) { 330168404Spjd /* 331168404Spjd * If the fs is zoned, only root can access it from the 332168404Spjd * global zone. 333168404Spjd */ 334168404Spjd if (secpolicy_zfs(cr) && zoned) 335168404Spjd return (EPERM); 336168404Spjd } else { 337168404Spjd /* 338168404Spjd * If we are in a local zone, the 'zoned' property must be set. 339168404Spjd */ 340168404Spjd if (!zoned) 341168404Spjd return (EPERM); 342168404Spjd 343168404Spjd /* must be writable by this zone */ 344168404Spjd if (!writable) 345168404Spjd return (EPERM); 346168404Spjd } 347168404Spjd return (0); 348168404Spjd} 349168404Spjd 350219089Spjdstatic int 351219089Spjdzfs_dozonecheck(const char *dataset, cred_t *cr) 352219089Spjd{ 353219089Spjd uint64_t zoned; 354219089Spjd 355219089Spjd if (dsl_prop_get_integer(dataset, "jailed", &zoned, NULL)) 356219089Spjd return (ENOENT); 357219089Spjd 358219089Spjd return (zfs_dozonecheck_impl(dataset, zoned, cr)); 359219089Spjd} 360219089Spjd 361219089Spjdstatic int 362219089Spjdzfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr) 363219089Spjd{ 364219089Spjd uint64_t zoned; 365219089Spjd 366219089Spjd rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 367219089Spjd if (dsl_prop_get_ds(ds, "jailed", 8, 1, &zoned, NULL)) { 368219089Spjd rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 369219089Spjd return (ENOENT); 370219089Spjd } 371219089Spjd rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 372219089Spjd 373219089Spjd return (zfs_dozonecheck_impl(dataset, zoned, cr)); 374219089Spjd} 375219089Spjd 376228103Smm/* 377228103Smm * If name ends in a '@', then require recursive permissions. 378228103Smm */ 379168404Spjdint 380185029Spjdzfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 381168404Spjd{ 382168404Spjd int error; 383228103Smm boolean_t descendent = B_FALSE; 384228103Smm dsl_dataset_t *ds; 385228103Smm char *at; 386168404Spjd 387228103Smm at = strchr(name, '@'); 388228103Smm if (at != NULL && at[1] == '\0') { 389228103Smm *at = '\0'; 390228103Smm descendent = B_TRUE; 391228103Smm } 392228103Smm 393228103Smm error = dsl_dataset_hold(name, FTAG, &ds); 394228103Smm if (at != NULL) 395228103Smm *at = '@'; 396228103Smm if (error != 0) 397228103Smm return (error); 398228103Smm 399228103Smm error = zfs_dozonecheck_ds(name, ds, cr); 400185029Spjd if (error == 0) { 401185029Spjd error = secpolicy_zfs(cr); 402185029Spjd if (error) 403228103Smm error = dsl_deleg_access_impl(ds, descendent, perm, cr); 404185029Spjd } 405228103Smm 406228103Smm dsl_dataset_rele(ds, FTAG); 407185029Spjd return (error); 408185029Spjd} 409185029Spjd 410219089Spjdint 411219089Spjdzfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds, 412219089Spjd const char *perm, cred_t *cr) 413219089Spjd{ 414219089Spjd int error; 415219089Spjd 416219089Spjd error = zfs_dozonecheck_ds(name, ds, cr); 417219089Spjd if (error == 0) { 418219089Spjd error = secpolicy_zfs(cr); 419219089Spjd if (error) 420228103Smm error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr); 421219089Spjd } 422219089Spjd return (error); 423219089Spjd} 424219089Spjd 425219089Spjd#ifdef SECLABEL 426219089Spjd/* 427219089Spjd * Policy for setting the security label property. 428219089Spjd * 429219089Spjd * Returns 0 for success, non-zero for access and other errors. 430219089Spjd */ 431185029Spjdstatic int 432219089Spjdzfs_set_slabel_policy(const char *name, char *strval, cred_t *cr) 433185029Spjd{ 434219089Spjd char ds_hexsl[MAXNAMELEN]; 435219089Spjd bslabel_t ds_sl, new_sl; 436219089Spjd boolean_t new_default = FALSE; 437219089Spjd uint64_t zoned; 438219089Spjd int needed_priv = -1; 439219089Spjd int error; 440219089Spjd 441219089Spjd /* First get the existing dataset label. */ 442219089Spjd error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 443219089Spjd 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 444219089Spjd if (error) 445219089Spjd return (EPERM); 446219089Spjd 447219089Spjd if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 448219089Spjd new_default = TRUE; 449219089Spjd 450219089Spjd /* The label must be translatable */ 451219089Spjd if (!new_default && (hexstr_to_label(strval, &new_sl) != 0)) 452219089Spjd return (EINVAL); 453219089Spjd 454185029Spjd /* 455219089Spjd * In a non-global zone, disallow attempts to set a label that 456219089Spjd * doesn't match that of the zone; otherwise no other checks 457219089Spjd * are needed. 458219089Spjd */ 459219089Spjd if (!INGLOBALZONE(curproc)) { 460219089Spjd if (new_default || !blequal(&new_sl, CR_SL(CRED()))) 461219089Spjd return (EPERM); 462219089Spjd return (0); 463219089Spjd } 464219089Spjd 465219089Spjd /* 466219089Spjd * For global-zone datasets (i.e., those whose zoned property is 467219089Spjd * "off", verify that the specified new label is valid for the 468219089Spjd * global zone. 469219089Spjd */ 470219089Spjd if (dsl_prop_get_integer(name, 471219089Spjd zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) 472219089Spjd return (EPERM); 473219089Spjd if (!zoned) { 474219089Spjd if (zfs_check_global_label(name, strval) != 0) 475219089Spjd return (EPERM); 476219089Spjd } 477219089Spjd 478219089Spjd /* 479219089Spjd * If the existing dataset label is nondefault, check if the 480219089Spjd * dataset is mounted (label cannot be changed while mounted). 481219089Spjd * Get the zfsvfs; if there isn't one, then the dataset isn't 482219089Spjd * mounted (or isn't a dataset, doesn't exist, ...). 483219089Spjd */ 484219089Spjd if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) { 485219089Spjd objset_t *os; 486219089Spjd static char *setsl_tag = "setsl_tag"; 487219089Spjd 488219089Spjd /* 489219089Spjd * Try to own the dataset; abort if there is any error, 490219089Spjd * (e.g., already mounted, in use, or other error). 491219089Spjd */ 492219089Spjd error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE, 493219089Spjd setsl_tag, &os); 494219089Spjd if (error) 495219089Spjd return (EPERM); 496219089Spjd 497219089Spjd dmu_objset_disown(os, setsl_tag); 498219089Spjd 499219089Spjd if (new_default) { 500219089Spjd needed_priv = PRIV_FILE_DOWNGRADE_SL; 501219089Spjd goto out_check; 502219089Spjd } 503219089Spjd 504219089Spjd if (hexstr_to_label(strval, &new_sl) != 0) 505219089Spjd return (EPERM); 506219089Spjd 507219089Spjd if (blstrictdom(&ds_sl, &new_sl)) 508219089Spjd needed_priv = PRIV_FILE_DOWNGRADE_SL; 509219089Spjd else if (blstrictdom(&new_sl, &ds_sl)) 510219089Spjd needed_priv = PRIV_FILE_UPGRADE_SL; 511219089Spjd } else { 512219089Spjd /* dataset currently has a default label */ 513219089Spjd if (!new_default) 514219089Spjd needed_priv = PRIV_FILE_UPGRADE_SL; 515219089Spjd } 516219089Spjd 517219089Spjdout_check: 518219089Spjd if (needed_priv != -1) 519219089Spjd return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL)); 520219089Spjd return (0); 521219089Spjd} 522219089Spjd#endif /* SECLABEL */ 523219089Spjd 524219089Spjdstatic int 525219089Spjdzfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval, 526219089Spjd cred_t *cr) 527219089Spjd{ 528219089Spjd char *strval; 529219089Spjd 530219089Spjd /* 531185029Spjd * Check permissions for special properties. 532185029Spjd */ 533185029Spjd switch (prop) { 534185029Spjd case ZFS_PROP_ZONED: 535185029Spjd /* 536185029Spjd * Disallow setting of 'zoned' from within a local zone. 537185029Spjd */ 538185029Spjd if (!INGLOBALZONE(curthread)) 539185029Spjd return (EPERM); 540185029Spjd break; 541185029Spjd 542185029Spjd case ZFS_PROP_QUOTA: 543185029Spjd if (!INGLOBALZONE(curthread)) { 544185029Spjd uint64_t zoned; 545185029Spjd char setpoint[MAXNAMELEN]; 546185029Spjd /* 547185029Spjd * Unprivileged users are allowed to modify the 548185029Spjd * quota on things *under* (ie. contained by) 549185029Spjd * the thing they own. 550185029Spjd */ 551219089Spjd if (dsl_prop_get_integer(dsname, "jailed", &zoned, 552185029Spjd setpoint)) 553185029Spjd return (EPERM); 554219089Spjd if (!zoned || strlen(dsname) <= strlen(setpoint)) 555185029Spjd return (EPERM); 556185029Spjd } 557185029Spjd break; 558219089Spjd 559219089Spjd case ZFS_PROP_MLSLABEL: 560219089Spjd#ifdef SECLABEL 561219089Spjd if (!is_system_labeled()) 562219089Spjd return (EPERM); 563219089Spjd 564219089Spjd if (nvpair_value_string(propval, &strval) == 0) { 565219089Spjd int err; 566219089Spjd 567219089Spjd err = zfs_set_slabel_policy(dsname, strval, CRED()); 568219089Spjd if (err != 0) 569219089Spjd return (err); 570219089Spjd } 571219089Spjd#else 572219089Spjd return (EOPNOTSUPP); 573219089Spjd#endif 574219089Spjd break; 575185029Spjd } 576185029Spjd 577219089Spjd return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr)); 578185029Spjd} 579185029Spjd 580185029Spjdint 581185029Spjdzfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) 582185029Spjd{ 583185029Spjd int error; 584185029Spjd 585185029Spjd error = zfs_dozonecheck(zc->zc_name, cr); 586185029Spjd if (error) 587168404Spjd return (error); 588168404Spjd 589185029Spjd /* 590185029Spjd * permission to set permissions will be evaluated later in 591185029Spjd * dsl_deleg_can_allow() 592185029Spjd */ 593185029Spjd return (0); 594168404Spjd} 595168404Spjd 596185029Spjdint 597185029Spjdzfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) 598185029Spjd{ 599219089Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 600219089Spjd ZFS_DELEG_PERM_ROLLBACK, cr)); 601185029Spjd} 602185029Spjd 603185029Spjdint 604185029Spjdzfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) 605185029Spjd{ 606219089Spjd spa_t *spa; 607219089Spjd dsl_pool_t *dp; 608219089Spjd dsl_dataset_t *ds; 609219089Spjd char *cp; 610219089Spjd int error; 611219089Spjd 612219089Spjd /* 613219089Spjd * Generate the current snapshot name from the given objsetid, then 614219089Spjd * use that name for the secpolicy/zone checks. 615219089Spjd */ 616219089Spjd cp = strchr(zc->zc_name, '@'); 617219089Spjd if (cp == NULL) 618219089Spjd return (EINVAL); 619219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 620219089Spjd if (error) 621219089Spjd return (error); 622219089Spjd 623219089Spjd dp = spa_get_dsl(spa); 624219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 625219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 626219089Spjd rw_exit(&dp->dp_config_rwlock); 627219089Spjd spa_close(spa, FTAG); 628219089Spjd if (error) 629219089Spjd return (error); 630219089Spjd 631219089Spjd dsl_dataset_name(ds, zc->zc_name); 632219089Spjd 633219089Spjd error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds, 634219089Spjd ZFS_DELEG_PERM_SEND, cr); 635219089Spjd dsl_dataset_rele(ds, FTAG); 636219089Spjd 637219089Spjd return (error); 638185029Spjd} 639185029Spjd 640209962Smmstatic int 641209962Smmzfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr) 642209962Smm{ 643209962Smm vnode_t *vp; 644209962Smm int error; 645209962Smm 646209962Smm if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 647209962Smm NO_FOLLOW, NULL, &vp)) != 0) 648209962Smm return (error); 649209962Smm 650209962Smm /* Now make sure mntpnt and dataset are ZFS */ 651209962Smm 652209962Smm if (strcmp(vp->v_vfsp->mnt_stat.f_fstypename, "zfs") != 0 || 653209962Smm (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 654209962Smm zc->zc_name) != 0)) { 655209962Smm VN_RELE(vp); 656209962Smm return (EPERM); 657209962Smm } 658209962Smm 659209962Smm VN_RELE(vp); 660209962Smm return (dsl_deleg_access(zc->zc_name, 661209962Smm ZFS_DELEG_PERM_SHARE, cr)); 662209962Smm} 663209962Smm 664185029Spjdint 665185029Spjdzfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) 666185029Spjd{ 667185029Spjd if (!INGLOBALZONE(curthread)) 668185029Spjd return (EPERM); 669185029Spjd 670185029Spjd if (secpolicy_nfs(cr) == 0) { 671185029Spjd return (0); 672185029Spjd } else { 673209962Smm return (zfs_secpolicy_deleg_share(zc, cr)); 674209962Smm } 675209962Smm} 676185029Spjd 677209962Smmint 678209962Smmzfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr) 679209962Smm{ 680209962Smm if (!INGLOBALZONE(curthread)) 681209962Smm return (EPERM); 682185029Spjd 683209962Smm if (secpolicy_smb(cr) == 0) { 684209962Smm return (0); 685209962Smm } else { 686209962Smm return (zfs_secpolicy_deleg_share(zc, cr)); 687185029Spjd } 688185029Spjd} 689185029Spjd 690168404Spjdstatic int 691185029Spjdzfs_get_parent(const char *datasetname, char *parent, int parentsize) 692168404Spjd{ 693168404Spjd char *cp; 694168404Spjd 695168404Spjd /* 696168404Spjd * Remove the @bla or /bla from the end of the name to get the parent. 697168404Spjd */ 698185029Spjd (void) strncpy(parent, datasetname, parentsize); 699185029Spjd cp = strrchr(parent, '@'); 700168404Spjd if (cp != NULL) { 701168404Spjd cp[0] = '\0'; 702168404Spjd } else { 703185029Spjd cp = strrchr(parent, '/'); 704168404Spjd if (cp == NULL) 705168404Spjd return (ENOENT); 706168404Spjd cp[0] = '\0'; 707185029Spjd } 708168404Spjd 709185029Spjd return (0); 710185029Spjd} 711185029Spjd 712185029Spjdint 713185029Spjdzfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 714185029Spjd{ 715185029Spjd int error; 716185029Spjd 717185029Spjd if ((error = zfs_secpolicy_write_perms(name, 718185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 719185029Spjd return (error); 720185029Spjd 721185029Spjd return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 722185029Spjd} 723185029Spjd 724185029Spjdstatic int 725185029Spjdzfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) 726185029Spjd{ 727185029Spjd return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 728185029Spjd} 729185029Spjd 730185029Spjd/* 731219089Spjd * Destroying snapshots with delegated permissions requires 732219089Spjd * descendent mount and destroy permissions. 733185029Spjd */ 734185029Spjdstatic int 735228103Smmzfs_secpolicy_destroy_recursive(zfs_cmd_t *zc, cred_t *cr) 736185029Spjd{ 737219089Spjd int error; 738219089Spjd char *dsname; 739219089Spjd 740228103Smm dsname = kmem_asprintf("%s@", zc->zc_name); 741219089Spjd 742219089Spjd error = zfs_secpolicy_destroy_perms(dsname, cr); 743219089Spjd 744222050Smm if (error == ENOENT) 745222050Smm error = zfs_secpolicy_destroy_perms(zc->zc_name, cr); 746222050Smm 747219089Spjd strfree(dsname); 748219089Spjd return (error); 749185029Spjd} 750185029Spjd 751185029Spjdint 752185029Spjdzfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 753185029Spjd{ 754219089Spjd char parentname[MAXNAMELEN]; 755185029Spjd int error; 756185029Spjd 757185029Spjd if ((error = zfs_secpolicy_write_perms(from, 758185029Spjd ZFS_DELEG_PERM_RENAME, cr)) != 0) 759185029Spjd return (error); 760185029Spjd 761185029Spjd if ((error = zfs_secpolicy_write_perms(from, 762185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 763185029Spjd return (error); 764185029Spjd 765185029Spjd if ((error = zfs_get_parent(to, parentname, 766185029Spjd sizeof (parentname))) != 0) 767185029Spjd return (error); 768185029Spjd 769185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 770185029Spjd ZFS_DELEG_PERM_CREATE, cr)) != 0) 771185029Spjd return (error); 772185029Spjd 773185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 774185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 775185029Spjd return (error); 776185029Spjd 777185029Spjd return (error); 778185029Spjd} 779185029Spjd 780185029Spjdstatic int 781185029Spjdzfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) 782185029Spjd{ 783240870Spjd char *at = NULL; 784240870Spjd int error; 785240870Spjd 786240870Spjd if ((zc->zc_cookie & 1) != 0) { 787240870Spjd /* 788240870Spjd * This is recursive rename, so the starting snapshot might 789240870Spjd * not exist. Check file system or volume permission instead. 790240870Spjd */ 791240870Spjd at = strchr(zc->zc_name, '@'); 792240870Spjd if (at == NULL) 793240870Spjd return (EINVAL); 794240870Spjd *at = '\0'; 795240870Spjd } 796240870Spjd 797240870Spjd error = zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr); 798240870Spjd 799240870Spjd if (at != NULL) 800240870Spjd *at = '@'; 801240870Spjd 802240870Spjd return (error); 803185029Spjd} 804185029Spjd 805185029Spjdstatic int 806185029Spjdzfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) 807185029Spjd{ 808219089Spjd char parentname[MAXNAMELEN]; 809185029Spjd objset_t *clone; 810185029Spjd int error; 811185029Spjd 812185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 813185029Spjd ZFS_DELEG_PERM_PROMOTE, cr); 814185029Spjd if (error) 815185029Spjd return (error); 816185029Spjd 817219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &clone); 818185029Spjd 819185029Spjd if (error == 0) { 820185029Spjd dsl_dataset_t *pclone = NULL; 821185029Spjd dsl_dir_t *dd; 822219089Spjd dd = clone->os_dsl_dataset->ds_dir; 823185029Spjd 824185029Spjd rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 825185029Spjd error = dsl_dataset_hold_obj(dd->dd_pool, 826185029Spjd dd->dd_phys->dd_origin_obj, FTAG, &pclone); 827185029Spjd rw_exit(&dd->dd_pool->dp_config_rwlock); 828185029Spjd if (error) { 829219089Spjd dmu_objset_rele(clone, FTAG); 830185029Spjd return (error); 831185029Spjd } 832185029Spjd 833185029Spjd error = zfs_secpolicy_write_perms(zc->zc_name, 834185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 835185029Spjd 836185029Spjd dsl_dataset_name(pclone, parentname); 837219089Spjd dmu_objset_rele(clone, FTAG); 838185029Spjd dsl_dataset_rele(pclone, FTAG); 839185029Spjd if (error == 0) 840185029Spjd error = zfs_secpolicy_write_perms(parentname, 841185029Spjd ZFS_DELEG_PERM_PROMOTE, cr); 842168404Spjd } 843185029Spjd return (error); 844185029Spjd} 845168404Spjd 846185029Spjdstatic int 847185029Spjdzfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) 848185029Spjd{ 849185029Spjd int error; 850185029Spjd 851185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 852185029Spjd ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 853185029Spjd return (error); 854185029Spjd 855185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 856185029Spjd ZFS_DELEG_PERM_MOUNT, cr)) != 0) 857185029Spjd return (error); 858185029Spjd 859185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 860185029Spjd ZFS_DELEG_PERM_CREATE, cr)); 861168404Spjd} 862168404Spjd 863185029Spjdint 864185029Spjdzfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 865185029Spjd{ 866219089Spjd return (zfs_secpolicy_write_perms(name, 867219089Spjd ZFS_DELEG_PERM_SNAPSHOT, cr)); 868185029Spjd} 869185029Spjd 870185029Spjdstatic int 871185029Spjdzfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) 872185029Spjd{ 873185029Spjd 874185029Spjd return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); 875185029Spjd} 876185029Spjd 877185029Spjdstatic int 878185029Spjdzfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) 879185029Spjd{ 880219089Spjd char parentname[MAXNAMELEN]; 881219089Spjd int error; 882185029Spjd 883185029Spjd if ((error = zfs_get_parent(zc->zc_name, parentname, 884185029Spjd sizeof (parentname))) != 0) 885185029Spjd return (error); 886185029Spjd 887185029Spjd if (zc->zc_value[0] != '\0') { 888185029Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_value, 889185029Spjd ZFS_DELEG_PERM_CLONE, cr)) != 0) 890185029Spjd return (error); 891185029Spjd } 892185029Spjd 893185029Spjd if ((error = zfs_secpolicy_write_perms(parentname, 894185029Spjd ZFS_DELEG_PERM_CREATE, cr)) != 0) 895185029Spjd return (error); 896185029Spjd 897185029Spjd error = zfs_secpolicy_write_perms(parentname, 898185029Spjd ZFS_DELEG_PERM_MOUNT, cr); 899185029Spjd 900185029Spjd return (error); 901185029Spjd} 902185029Spjd 903185029Spjdstatic int 904185029Spjdzfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) 905185029Spjd{ 906185029Spjd int error; 907185029Spjd 908185029Spjd error = secpolicy_fs_unmount(cr, NULL); 909185029Spjd if (error) { 910185029Spjd error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); 911185029Spjd } 912185029Spjd return (error); 913185029Spjd} 914185029Spjd 915168404Spjd/* 916168404Spjd * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 917168404Spjd * SYS_CONFIG privilege, which is not available in a local zone. 918168404Spjd */ 919168404Spjd/* ARGSUSED */ 920168404Spjdstatic int 921185029Spjdzfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) 922168404Spjd{ 923168404Spjd if (secpolicy_sys_config(cr, B_FALSE) != 0) 924168404Spjd return (EPERM); 925168404Spjd 926168404Spjd return (0); 927168404Spjd} 928168404Spjd 929168404Spjd/* 930219089Spjd * Policy for object to name lookups. 931185029Spjd */ 932219089Spjd/* ARGSUSED */ 933185029Spjdstatic int 934219089Spjdzfs_secpolicy_diff(zfs_cmd_t *zc, cred_t *cr) 935185029Spjd{ 936219089Spjd int error; 937185029Spjd 938219089Spjd if ((error = secpolicy_sys_config(cr, B_FALSE)) == 0) 939219089Spjd return (0); 940219089Spjd 941219089Spjd error = zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_DIFF, cr); 942219089Spjd return (error); 943185029Spjd} 944185029Spjd 945185029Spjd/* 946168404Spjd * Policy for fault injection. Requires all privileges. 947168404Spjd */ 948168404Spjd/* ARGSUSED */ 949168404Spjdstatic int 950185029Spjdzfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) 951168404Spjd{ 952168404Spjd return (secpolicy_zinject(cr)); 953168404Spjd} 954168404Spjd 955185029Spjdstatic int 956185029Spjdzfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) 957185029Spjd{ 958185029Spjd zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 959185029Spjd 960185029Spjd if (prop == ZPROP_INVAL) { 961185029Spjd if (!zfs_prop_user(zc->zc_value)) 962185029Spjd return (EINVAL); 963185029Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 964185029Spjd ZFS_DELEG_PERM_USERPROP, cr)); 965185029Spjd } else { 966219089Spjd return (zfs_secpolicy_setprop(zc->zc_name, prop, 967219089Spjd NULL, cr)); 968185029Spjd } 969185029Spjd} 970185029Spjd 971168404Spjdstatic int 972209962Smmzfs_secpolicy_userspace_one(zfs_cmd_t *zc, cred_t *cr) 973209962Smm{ 974209962Smm int err = zfs_secpolicy_read(zc, cr); 975209962Smm if (err) 976209962Smm return (err); 977209962Smm 978209962Smm if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 979209962Smm return (EINVAL); 980209962Smm 981209962Smm if (zc->zc_value[0] == 0) { 982209962Smm /* 983209962Smm * They are asking about a posix uid/gid. If it's 984209962Smm * themself, allow it. 985209962Smm */ 986209962Smm if (zc->zc_objset_type == ZFS_PROP_USERUSED || 987209962Smm zc->zc_objset_type == ZFS_PROP_USERQUOTA) { 988209962Smm if (zc->zc_guid == crgetuid(cr)) 989209962Smm return (0); 990209962Smm } else { 991209962Smm if (groupmember(zc->zc_guid, cr)) 992209962Smm return (0); 993209962Smm } 994209962Smm } 995209962Smm 996209962Smm return (zfs_secpolicy_write_perms(zc->zc_name, 997209962Smm userquota_perms[zc->zc_objset_type], cr)); 998209962Smm} 999209962Smm 1000209962Smmstatic int 1001209962Smmzfs_secpolicy_userspace_many(zfs_cmd_t *zc, cred_t *cr) 1002209962Smm{ 1003209962Smm int err = zfs_secpolicy_read(zc, cr); 1004209962Smm if (err) 1005209962Smm return (err); 1006209962Smm 1007209962Smm if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 1008209962Smm return (EINVAL); 1009209962Smm 1010209962Smm return (zfs_secpolicy_write_perms(zc->zc_name, 1011209962Smm userquota_perms[zc->zc_objset_type], cr)); 1012209962Smm} 1013209962Smm 1014209962Smmstatic int 1015209962Smmzfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, cred_t *cr) 1016209962Smm{ 1017219089Spjd return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, 1018219089Spjd NULL, cr)); 1019209962Smm} 1020209962Smm 1021219089Spjdstatic int 1022219089Spjdzfs_secpolicy_hold(zfs_cmd_t *zc, cred_t *cr) 1023219089Spjd{ 1024219089Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 1025219089Spjd ZFS_DELEG_PERM_HOLD, cr)); 1026219089Spjd} 1027219089Spjd 1028219089Spjdstatic int 1029219089Spjdzfs_secpolicy_release(zfs_cmd_t *zc, cred_t *cr) 1030219089Spjd{ 1031219089Spjd return (zfs_secpolicy_write_perms(zc->zc_name, 1032219089Spjd ZFS_DELEG_PERM_RELEASE, cr)); 1033219089Spjd} 1034219089Spjd 1035168404Spjd/* 1036219089Spjd * Policy for allowing temporary snapshots to be taken or released 1037219089Spjd */ 1038219089Spjdstatic int 1039219089Spjdzfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, cred_t *cr) 1040219089Spjd{ 1041219089Spjd /* 1042219089Spjd * A temporary snapshot is the same as a snapshot, 1043219089Spjd * hold, destroy and release all rolled into one. 1044219089Spjd * Delegated diff alone is sufficient that we allow this. 1045219089Spjd */ 1046219089Spjd int error; 1047219089Spjd 1048219089Spjd if ((error = zfs_secpolicy_write_perms(zc->zc_name, 1049219089Spjd ZFS_DELEG_PERM_DIFF, cr)) == 0) 1050219089Spjd return (0); 1051219089Spjd 1052219089Spjd error = zfs_secpolicy_snapshot(zc, cr); 1053219089Spjd if (!error) 1054219089Spjd error = zfs_secpolicy_hold(zc, cr); 1055219089Spjd if (!error) 1056219089Spjd error = zfs_secpolicy_release(zc, cr); 1057219089Spjd if (!error) 1058219089Spjd error = zfs_secpolicy_destroy(zc, cr); 1059219089Spjd return (error); 1060219089Spjd} 1061219089Spjd 1062219089Spjd/* 1063168404Spjd * Returns the nvlist as specified by the user in the zfs_cmd_t. 1064168404Spjd */ 1065168404Spjdstatic int 1066219089Spjdget_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) 1067168404Spjd{ 1068168404Spjd char *packed; 1069168404Spjd int error; 1070185029Spjd nvlist_t *list = NULL; 1071168404Spjd 1072168404Spjd /* 1073168404Spjd * Read in and unpack the user-supplied nvlist. 1074168404Spjd */ 1075185029Spjd if (size == 0) 1076168404Spjd return (EINVAL); 1077168404Spjd 1078168404Spjd packed = kmem_alloc(size, KM_SLEEP); 1079168404Spjd 1080219089Spjd if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 1081219089Spjd iflag)) != 0) { 1082168404Spjd kmem_free(packed, size); 1083168404Spjd return (error); 1084168404Spjd } 1085168404Spjd 1086185029Spjd if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 1087168404Spjd kmem_free(packed, size); 1088168404Spjd return (error); 1089168404Spjd } 1090168404Spjd 1091168404Spjd kmem_free(packed, size); 1092168404Spjd 1093185029Spjd *nvp = list; 1094168404Spjd return (0); 1095168404Spjd} 1096168404Spjd 1097168404Spjdstatic int 1098219089Spjdfit_error_list(zfs_cmd_t *zc, nvlist_t **errors) 1099219089Spjd{ 1100219089Spjd size_t size; 1101219089Spjd 1102219089Spjd VERIFY(nvlist_size(*errors, &size, NV_ENCODE_NATIVE) == 0); 1103219089Spjd 1104219089Spjd if (size > zc->zc_nvlist_dst_size) { 1105219089Spjd nvpair_t *more_errors; 1106219089Spjd int n = 0; 1107219089Spjd 1108219089Spjd if (zc->zc_nvlist_dst_size < 1024) 1109219089Spjd return (ENOMEM); 1110219089Spjd 1111219089Spjd VERIFY(nvlist_add_int32(*errors, ZPROP_N_MORE_ERRORS, 0) == 0); 1112219089Spjd more_errors = nvlist_prev_nvpair(*errors, NULL); 1113219089Spjd 1114219089Spjd do { 1115219089Spjd nvpair_t *pair = nvlist_prev_nvpair(*errors, 1116219089Spjd more_errors); 1117219089Spjd VERIFY(nvlist_remove_nvpair(*errors, pair) == 0); 1118219089Spjd n++; 1119219089Spjd VERIFY(nvlist_size(*errors, &size, 1120219089Spjd NV_ENCODE_NATIVE) == 0); 1121219089Spjd } while (size > zc->zc_nvlist_dst_size); 1122219089Spjd 1123219089Spjd VERIFY(nvlist_remove_nvpair(*errors, more_errors) == 0); 1124219089Spjd VERIFY(nvlist_add_int32(*errors, ZPROP_N_MORE_ERRORS, n) == 0); 1125219089Spjd ASSERT(nvlist_size(*errors, &size, NV_ENCODE_NATIVE) == 0); 1126219089Spjd ASSERT(size <= zc->zc_nvlist_dst_size); 1127219089Spjd } 1128219089Spjd 1129219089Spjd return (0); 1130219089Spjd} 1131219089Spjd 1132219089Spjdstatic int 1133168404Spjdput_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 1134168404Spjd{ 1135168404Spjd char *packed = NULL; 1136219089Spjd int error = 0; 1137168404Spjd size_t size; 1138168404Spjd 1139168404Spjd VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 1140168404Spjd 1141168404Spjd if (size > zc->zc_nvlist_dst_size) { 1142168404Spjd /* 1143168404Spjd * Solaris returns ENOMEM here, because even if an error is 1144168404Spjd * returned from an ioctl(2), new zc_nvlist_dst_size will be 1145168404Spjd * passed to the userland. This is not the case for FreeBSD. 1146168404Spjd * We need to return 0, so the kernel will copy the 1147168404Spjd * zc_nvlist_dst_size back and the userland can discover that a 1148168404Spjd * bigger buffer is needed. 1149168404Spjd */ 1150168404Spjd error = 0; 1151168404Spjd } else { 1152185029Spjd packed = kmem_alloc(size, KM_SLEEP); 1153168404Spjd VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 1154168404Spjd KM_SLEEP) == 0); 1155219089Spjd if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 1156219089Spjd size, zc->zc_iflags) != 0) 1157219089Spjd error = EFAULT; 1158168404Spjd kmem_free(packed, size); 1159168404Spjd } 1160168404Spjd 1161168404Spjd zc->zc_nvlist_dst_size = size; 1162168404Spjd return (error); 1163168404Spjd} 1164168404Spjd 1165168404Spjdstatic int 1166219089Spjdgetzfsvfs(const char *dsname, zfsvfs_t **zfvp) 1167209962Smm{ 1168209962Smm objset_t *os; 1169209962Smm int error; 1170209962Smm 1171219089Spjd error = dmu_objset_hold(dsname, FTAG, &os); 1172209962Smm if (error) 1173209962Smm return (error); 1174219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 1175219089Spjd dmu_objset_rele(os, FTAG); 1176219089Spjd return (EINVAL); 1177219089Spjd } 1178209962Smm 1179219089Spjd mutex_enter(&os->os_user_ptr_lock); 1180219089Spjd *zfvp = dmu_objset_get_user(os); 1181219089Spjd if (*zfvp) { 1182219089Spjd VFS_HOLD((*zfvp)->z_vfs); 1183209962Smm } else { 1184209962Smm error = ESRCH; 1185209962Smm } 1186219089Spjd mutex_exit(&os->os_user_ptr_lock); 1187219089Spjd dmu_objset_rele(os, FTAG); 1188209962Smm return (error); 1189209962Smm} 1190209962Smm 1191209962Smm/* 1192209962Smm * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 1193209962Smm * case its z_vfs will be NULL, and it will be opened as the owner. 1194236884Smm * If 'writer' is set, the z_teardown_lock will be held for RW_WRITER, 1195236884Smm * which prevents all vnode ops from running. 1196209962Smm */ 1197209962Smmstatic int 1198219089Spjdzfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer) 1199209962Smm{ 1200209962Smm int error = 0; 1201209962Smm 1202219089Spjd if (getzfsvfs(name, zfvp) != 0) 1203219089Spjd error = zfsvfs_create(name, zfvp); 1204209962Smm if (error == 0) { 1205219089Spjd rrw_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER : 1206219089Spjd RW_READER, tag); 1207219089Spjd if ((*zfvp)->z_unmounted) { 1208209962Smm /* 1209209962Smm * XXX we could probably try again, since the unmounting 1210209962Smm * thread should be just about to disassociate the 1211209962Smm * objset from the zfsvfs. 1212209962Smm */ 1213219089Spjd rrw_exit(&(*zfvp)->z_teardown_lock, tag); 1214209962Smm return (EBUSY); 1215209962Smm } 1216209962Smm } 1217209962Smm return (error); 1218209962Smm} 1219209962Smm 1220209962Smmstatic void 1221209962Smmzfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 1222209962Smm{ 1223209962Smm rrw_exit(&zfsvfs->z_teardown_lock, tag); 1224209962Smm 1225209962Smm if (zfsvfs->z_vfs) { 1226209962Smm VFS_RELE(zfsvfs->z_vfs); 1227209962Smm } else { 1228219089Spjd dmu_objset_disown(zfsvfs->z_os, zfsvfs); 1229209962Smm zfsvfs_free(zfsvfs); 1230209962Smm } 1231209962Smm} 1232209962Smm 1233209962Smmstatic int 1234168404Spjdzfs_ioc_pool_create(zfs_cmd_t *zc) 1235168404Spjd{ 1236168404Spjd int error; 1237185029Spjd nvlist_t *config, *props = NULL; 1238185029Spjd nvlist_t *rootprops = NULL; 1239185029Spjd nvlist_t *zplprops = NULL; 1240185029Spjd char *buf; 1241168404Spjd 1242185029Spjd if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1243219089Spjd zc->zc_iflags, &config)) 1244168404Spjd return (error); 1245168404Spjd 1246185029Spjd if (zc->zc_nvlist_src_size != 0 && (error = 1247219089Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1248219089Spjd zc->zc_iflags, &props))) { 1249185029Spjd nvlist_free(config); 1250185029Spjd return (error); 1251185029Spjd } 1252168404Spjd 1253185029Spjd if (props) { 1254185029Spjd nvlist_t *nvl = NULL; 1255185029Spjd uint64_t version = SPA_VERSION; 1256185029Spjd 1257185029Spjd (void) nvlist_lookup_uint64(props, 1258185029Spjd zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 1259236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1260185029Spjd error = EINVAL; 1261185029Spjd goto pool_props_bad; 1262185029Spjd } 1263185029Spjd (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 1264185029Spjd if (nvl) { 1265185029Spjd error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 1266185029Spjd if (error != 0) { 1267185029Spjd nvlist_free(config); 1268185029Spjd nvlist_free(props); 1269185029Spjd return (error); 1270185029Spjd } 1271185029Spjd (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 1272185029Spjd } 1273185029Spjd VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1274185029Spjd error = zfs_fill_zplprops_root(version, rootprops, 1275185029Spjd zplprops, NULL); 1276185029Spjd if (error) 1277185029Spjd goto pool_props_bad; 1278185029Spjd } 1279185029Spjd 1280185029Spjd buf = history_str_get(zc); 1281185029Spjd 1282185029Spjd error = spa_create(zc->zc_name, config, props, buf, zplprops); 1283185029Spjd 1284185029Spjd /* 1285185029Spjd * Set the remaining root properties 1286185029Spjd */ 1287219089Spjd if (!error && (error = zfs_set_prop_nvlist(zc->zc_name, 1288219089Spjd ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) 1289185029Spjd (void) spa_destroy(zc->zc_name); 1290185029Spjd 1291185029Spjd if (buf != NULL) 1292185029Spjd history_str_free(buf); 1293185029Spjd 1294185029Spjdpool_props_bad: 1295185029Spjd nvlist_free(rootprops); 1296185029Spjd nvlist_free(zplprops); 1297168404Spjd nvlist_free(config); 1298185029Spjd nvlist_free(props); 1299168404Spjd 1300168404Spjd return (error); 1301168404Spjd} 1302168404Spjd 1303168404Spjdstatic int 1304168404Spjdzfs_ioc_pool_destroy(zfs_cmd_t *zc) 1305168404Spjd{ 1306185029Spjd int error; 1307185029Spjd zfs_log_history(zc); 1308185029Spjd error = spa_destroy(zc->zc_name); 1309219089Spjd if (error == 0) 1310219089Spjd zvol_remove_minors(zc->zc_name); 1311185029Spjd return (error); 1312168404Spjd} 1313168404Spjd 1314168404Spjdstatic int 1315168404Spjdzfs_ioc_pool_import(zfs_cmd_t *zc) 1316168404Spjd{ 1317185029Spjd nvlist_t *config, *props = NULL; 1318168404Spjd uint64_t guid; 1319219089Spjd int error; 1320168404Spjd 1321185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1322219089Spjd zc->zc_iflags, &config)) != 0) 1323168404Spjd return (error); 1324168404Spjd 1325185029Spjd if (zc->zc_nvlist_src_size != 0 && (error = 1326219089Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1327219089Spjd zc->zc_iflags, &props))) { 1328185029Spjd nvlist_free(config); 1329185029Spjd return (error); 1330185029Spjd } 1331185029Spjd 1332168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 1333168404Spjd guid != zc->zc_guid) 1334168404Spjd error = EINVAL; 1335168404Spjd else 1336219089Spjd error = spa_import(zc->zc_name, config, props, zc->zc_cookie); 1337168404Spjd 1338219089Spjd if (zc->zc_nvlist_dst != 0) { 1339219089Spjd int err; 1340219089Spjd 1341219089Spjd if ((err = put_nvlist(zc, config)) != 0) 1342219089Spjd error = err; 1343219089Spjd } 1344219089Spjd 1345168404Spjd nvlist_free(config); 1346168404Spjd 1347185029Spjd if (props) 1348185029Spjd nvlist_free(props); 1349185029Spjd 1350168404Spjd return (error); 1351168404Spjd} 1352168404Spjd 1353168404Spjdstatic int 1354168404Spjdzfs_ioc_pool_export(zfs_cmd_t *zc) 1355168404Spjd{ 1356185029Spjd int error; 1357185029Spjd boolean_t force = (boolean_t)zc->zc_cookie; 1358207670Smm boolean_t hardforce = (boolean_t)zc->zc_guid; 1359185029Spjd 1360185029Spjd zfs_log_history(zc); 1361207670Smm error = spa_export(zc->zc_name, NULL, force, hardforce); 1362219089Spjd if (error == 0) 1363219089Spjd zvol_remove_minors(zc->zc_name); 1364185029Spjd return (error); 1365168404Spjd} 1366168404Spjd 1367168404Spjdstatic int 1368168404Spjdzfs_ioc_pool_configs(zfs_cmd_t *zc) 1369168404Spjd{ 1370168404Spjd nvlist_t *configs; 1371168404Spjd int error; 1372168404Spjd 1373168404Spjd if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1374168404Spjd return (EEXIST); 1375168404Spjd 1376168404Spjd error = put_nvlist(zc, configs); 1377168404Spjd 1378168404Spjd nvlist_free(configs); 1379168404Spjd 1380168404Spjd return (error); 1381168404Spjd} 1382168404Spjd 1383236884Smm/* 1384236884Smm * inputs: 1385236884Smm * zc_name name of the pool 1386236884Smm * 1387236884Smm * outputs: 1388236884Smm * zc_cookie real errno 1389236884Smm * zc_nvlist_dst config nvlist 1390236884Smm * zc_nvlist_dst_size size of config nvlist 1391236884Smm */ 1392168404Spjdstatic int 1393168404Spjdzfs_ioc_pool_stats(zfs_cmd_t *zc) 1394168404Spjd{ 1395168404Spjd nvlist_t *config; 1396168404Spjd int error; 1397168404Spjd int ret = 0; 1398168404Spjd 1399168404Spjd error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 1400168404Spjd sizeof (zc->zc_value)); 1401168404Spjd 1402168404Spjd if (config != NULL) { 1403168404Spjd ret = put_nvlist(zc, config); 1404168404Spjd nvlist_free(config); 1405168404Spjd 1406168404Spjd /* 1407168404Spjd * The config may be present even if 'error' is non-zero. 1408168404Spjd * In this case we return success, and preserve the real errno 1409168404Spjd * in 'zc_cookie'. 1410168404Spjd */ 1411168404Spjd zc->zc_cookie = error; 1412168404Spjd } else { 1413168404Spjd ret = error; 1414168404Spjd } 1415168404Spjd 1416168404Spjd return (ret); 1417168404Spjd} 1418168404Spjd 1419168404Spjd/* 1420168404Spjd * Try to import the given pool, returning pool stats as appropriate so that 1421168404Spjd * user land knows which devices are available and overall pool health. 1422168404Spjd */ 1423168404Spjdstatic int 1424168404Spjdzfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1425168404Spjd{ 1426168404Spjd nvlist_t *tryconfig, *config; 1427168404Spjd int error; 1428168404Spjd 1429185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1430219089Spjd zc->zc_iflags, &tryconfig)) != 0) 1431168404Spjd return (error); 1432168404Spjd 1433168404Spjd config = spa_tryimport(tryconfig); 1434168404Spjd 1435168404Spjd nvlist_free(tryconfig); 1436168404Spjd 1437168404Spjd if (config == NULL) 1438168404Spjd return (EINVAL); 1439168404Spjd 1440168404Spjd error = put_nvlist(zc, config); 1441168404Spjd nvlist_free(config); 1442168404Spjd 1443168404Spjd return (error); 1444168404Spjd} 1445168404Spjd 1446219089Spjd/* 1447219089Spjd * inputs: 1448219089Spjd * zc_name name of the pool 1449219089Spjd * zc_cookie scan func (pool_scan_func_t) 1450219089Spjd */ 1451168404Spjdstatic int 1452219089Spjdzfs_ioc_pool_scan(zfs_cmd_t *zc) 1453168404Spjd{ 1454168404Spjd spa_t *spa; 1455168404Spjd int error; 1456168404Spjd 1457168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1458168404Spjd return (error); 1459168404Spjd 1460219089Spjd if (zc->zc_cookie == POOL_SCAN_NONE) 1461219089Spjd error = spa_scan_stop(spa); 1462219089Spjd else 1463219089Spjd error = spa_scan(spa, zc->zc_cookie); 1464168404Spjd 1465168404Spjd spa_close(spa, FTAG); 1466168404Spjd 1467168404Spjd return (error); 1468168404Spjd} 1469168404Spjd 1470168404Spjdstatic int 1471168404Spjdzfs_ioc_pool_freeze(zfs_cmd_t *zc) 1472168404Spjd{ 1473168404Spjd spa_t *spa; 1474168404Spjd int error; 1475168404Spjd 1476168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1477168404Spjd if (error == 0) { 1478168404Spjd spa_freeze(spa); 1479168404Spjd spa_close(spa, FTAG); 1480168404Spjd } 1481168404Spjd return (error); 1482168404Spjd} 1483168404Spjd 1484168404Spjdstatic int 1485168404Spjdzfs_ioc_pool_upgrade(zfs_cmd_t *zc) 1486168404Spjd{ 1487168404Spjd spa_t *spa; 1488168404Spjd int error; 1489168404Spjd 1490168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1491168404Spjd return (error); 1492168404Spjd 1493236884Smm if (zc->zc_cookie < spa_version(spa) || 1494236884Smm !SPA_VERSION_IS_SUPPORTED(zc->zc_cookie)) { 1495185029Spjd spa_close(spa, FTAG); 1496185029Spjd return (EINVAL); 1497185029Spjd } 1498168404Spjd 1499185029Spjd spa_upgrade(spa, zc->zc_cookie); 1500168404Spjd spa_close(spa, FTAG); 1501168404Spjd 1502168404Spjd return (error); 1503168404Spjd} 1504168404Spjd 1505168404Spjdstatic int 1506168404Spjdzfs_ioc_pool_get_history(zfs_cmd_t *zc) 1507168404Spjd{ 1508168404Spjd spa_t *spa; 1509168404Spjd char *hist_buf; 1510168404Spjd uint64_t size; 1511168404Spjd int error; 1512168404Spjd 1513168404Spjd if ((size = zc->zc_history_len) == 0) 1514168404Spjd return (EINVAL); 1515168404Spjd 1516168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1517168404Spjd return (error); 1518168404Spjd 1519185029Spjd if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1520168404Spjd spa_close(spa, FTAG); 1521168404Spjd return (ENOTSUP); 1522168404Spjd } 1523168404Spjd 1524168404Spjd hist_buf = kmem_alloc(size, KM_SLEEP); 1525168404Spjd if ((error = spa_history_get(spa, &zc->zc_history_offset, 1526168404Spjd &zc->zc_history_len, hist_buf)) == 0) { 1527219089Spjd error = ddi_copyout(hist_buf, 1528219089Spjd (void *)(uintptr_t)zc->zc_history, 1529219089Spjd zc->zc_history_len, zc->zc_iflags); 1530168404Spjd } 1531168404Spjd 1532168404Spjd spa_close(spa, FTAG); 1533168404Spjd kmem_free(hist_buf, size); 1534168404Spjd return (error); 1535168404Spjd} 1536168404Spjd 1537168404Spjdstatic int 1538228103Smmzfs_ioc_pool_reguid(zfs_cmd_t *zc) 1539228103Smm{ 1540228103Smm spa_t *spa; 1541228103Smm int error; 1542228103Smm 1543228103Smm error = spa_open(zc->zc_name, &spa, FTAG); 1544228103Smm if (error == 0) { 1545228103Smm error = spa_change_guid(spa); 1546228103Smm spa_close(spa, FTAG); 1547228103Smm } 1548228103Smm return (error); 1549228103Smm} 1550228103Smm 1551228103Smmstatic int 1552168404Spjdzfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 1553168404Spjd{ 1554168404Spjd int error; 1555168404Spjd 1556168404Spjd if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 1557168404Spjd return (error); 1558168404Spjd 1559168404Spjd return (0); 1560168404Spjd} 1561168404Spjd 1562219089Spjd/* 1563219089Spjd * inputs: 1564219089Spjd * zc_name name of filesystem 1565219089Spjd * zc_obj object to find 1566219089Spjd * 1567219089Spjd * outputs: 1568219089Spjd * zc_value name of object 1569219089Spjd */ 1570168404Spjdstatic int 1571168404Spjdzfs_ioc_obj_to_path(zfs_cmd_t *zc) 1572168404Spjd{ 1573219089Spjd objset_t *os; 1574168404Spjd int error; 1575168404Spjd 1576219089Spjd /* XXX reading from objset not owned */ 1577219089Spjd if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0) 1578168404Spjd return (error); 1579219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 1580219089Spjd dmu_objset_rele(os, FTAG); 1581219089Spjd return (EINVAL); 1582219089Spjd } 1583219089Spjd error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value, 1584168404Spjd sizeof (zc->zc_value)); 1585219089Spjd dmu_objset_rele(os, FTAG); 1586168404Spjd 1587168404Spjd return (error); 1588168404Spjd} 1589168404Spjd 1590219089Spjd/* 1591219089Spjd * inputs: 1592219089Spjd * zc_name name of filesystem 1593219089Spjd * zc_obj object to find 1594219089Spjd * 1595219089Spjd * outputs: 1596219089Spjd * zc_stat stats on object 1597219089Spjd * zc_value path to object 1598219089Spjd */ 1599168404Spjdstatic int 1600219089Spjdzfs_ioc_obj_to_stats(zfs_cmd_t *zc) 1601219089Spjd{ 1602219089Spjd objset_t *os; 1603219089Spjd int error; 1604219089Spjd 1605219089Spjd /* XXX reading from objset not owned */ 1606219089Spjd if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0) 1607219089Spjd return (error); 1608219089Spjd if (dmu_objset_type(os) != DMU_OST_ZFS) { 1609219089Spjd dmu_objset_rele(os, FTAG); 1610219089Spjd return (EINVAL); 1611219089Spjd } 1612219089Spjd error = zfs_obj_to_stats(os, zc->zc_obj, &zc->zc_stat, zc->zc_value, 1613219089Spjd sizeof (zc->zc_value)); 1614219089Spjd dmu_objset_rele(os, FTAG); 1615219089Spjd 1616219089Spjd return (error); 1617219089Spjd} 1618219089Spjd 1619219089Spjdstatic int 1620168404Spjdzfs_ioc_vdev_add(zfs_cmd_t *zc) 1621168404Spjd{ 1622168404Spjd spa_t *spa; 1623168404Spjd int error; 1624185029Spjd nvlist_t *config, **l2cache, **spares; 1625185029Spjd uint_t nl2cache = 0, nspares = 0; 1626168404Spjd 1627168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1628168404Spjd if (error != 0) 1629168404Spjd return (error); 1630168404Spjd 1631185029Spjd error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1632219089Spjd zc->zc_iflags, &config); 1633185029Spjd (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1634185029Spjd &l2cache, &nl2cache); 1635185029Spjd 1636185029Spjd (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1637185029Spjd &spares, &nspares); 1638185029Spjd 1639168404Spjd /* 1640168404Spjd * A root pool with concatenated devices is not supported. 1641185029Spjd * Thus, can not add a device to a root pool. 1642185029Spjd * 1643185029Spjd * Intent log device can not be added to a rootpool because 1644185029Spjd * during mountroot, zil is replayed, a seperated log device 1645185029Spjd * can not be accessed during the mountroot time. 1646185029Spjd * 1647185029Spjd * l2cache and spare devices are ok to be added to a rootpool. 1648168404Spjd */ 1649219089Spjd if (spa_bootfs(spa) != 0 && nl2cache == 0 && nspares == 0) { 1650219089Spjd nvlist_free(config); 1651168404Spjd spa_close(spa, FTAG); 1652168404Spjd return (EDOM); 1653168404Spjd } 1654168404Spjd 1655185029Spjd if (error == 0) { 1656168404Spjd error = spa_vdev_add(spa, config); 1657168404Spjd nvlist_free(config); 1658168404Spjd } 1659168404Spjd spa_close(spa, FTAG); 1660168404Spjd return (error); 1661168404Spjd} 1662168404Spjd 1663219089Spjd/* 1664219089Spjd * inputs: 1665219089Spjd * zc_name name of the pool 1666219089Spjd * zc_nvlist_conf nvlist of devices to remove 1667219089Spjd * zc_cookie to stop the remove? 1668219089Spjd */ 1669168404Spjdstatic int 1670168404Spjdzfs_ioc_vdev_remove(zfs_cmd_t *zc) 1671168404Spjd{ 1672168404Spjd spa_t *spa; 1673168404Spjd int error; 1674168404Spjd 1675168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1676168404Spjd if (error != 0) 1677168404Spjd return (error); 1678168404Spjd error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 1679168404Spjd spa_close(spa, FTAG); 1680168404Spjd return (error); 1681168404Spjd} 1682168404Spjd 1683168404Spjdstatic int 1684185029Spjdzfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1685168404Spjd{ 1686168404Spjd spa_t *spa; 1687168404Spjd int error; 1688185029Spjd vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1689168404Spjd 1690168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1691168404Spjd return (error); 1692185029Spjd switch (zc->zc_cookie) { 1693185029Spjd case VDEV_STATE_ONLINE: 1694185029Spjd error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 1695185029Spjd break; 1696168404Spjd 1697185029Spjd case VDEV_STATE_OFFLINE: 1698185029Spjd error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 1699185029Spjd break; 1700168404Spjd 1701185029Spjd case VDEV_STATE_FAULTED: 1702219089Spjd if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1703219089Spjd zc->zc_obj != VDEV_AUX_EXTERNAL) 1704219089Spjd zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1705219089Spjd 1706219089Spjd error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); 1707185029Spjd break; 1708185029Spjd 1709185029Spjd case VDEV_STATE_DEGRADED: 1710219089Spjd if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1711219089Spjd zc->zc_obj != VDEV_AUX_EXTERNAL) 1712219089Spjd zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1713219089Spjd 1714219089Spjd error = vdev_degrade(spa, zc->zc_guid, zc->zc_obj); 1715185029Spjd break; 1716185029Spjd 1717185029Spjd default: 1718185029Spjd error = EINVAL; 1719185029Spjd } 1720185029Spjd zc->zc_cookie = newstate; 1721168404Spjd spa_close(spa, FTAG); 1722168404Spjd return (error); 1723168404Spjd} 1724168404Spjd 1725168404Spjdstatic int 1726168404Spjdzfs_ioc_vdev_attach(zfs_cmd_t *zc) 1727168404Spjd{ 1728168404Spjd spa_t *spa; 1729168404Spjd int replacing = zc->zc_cookie; 1730168404Spjd nvlist_t *config; 1731168404Spjd int error; 1732168404Spjd 1733168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1734168404Spjd return (error); 1735168404Spjd 1736185029Spjd if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1737219089Spjd zc->zc_iflags, &config)) == 0) { 1738168404Spjd error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 1739168404Spjd nvlist_free(config); 1740168404Spjd } 1741168404Spjd 1742168404Spjd spa_close(spa, FTAG); 1743168404Spjd return (error); 1744168404Spjd} 1745168404Spjd 1746168404Spjdstatic int 1747168404Spjdzfs_ioc_vdev_detach(zfs_cmd_t *zc) 1748168404Spjd{ 1749168404Spjd spa_t *spa; 1750168404Spjd int error; 1751168404Spjd 1752168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1753168404Spjd return (error); 1754168404Spjd 1755209962Smm error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 1756168404Spjd 1757168404Spjd spa_close(spa, FTAG); 1758168404Spjd return (error); 1759168404Spjd} 1760168404Spjd 1761168404Spjdstatic int 1762219089Spjdzfs_ioc_vdev_split(zfs_cmd_t *zc) 1763219089Spjd{ 1764219089Spjd spa_t *spa; 1765219089Spjd nvlist_t *config, *props = NULL; 1766219089Spjd int error; 1767219089Spjd boolean_t exp = !!(zc->zc_cookie & ZPOOL_EXPORT_AFTER_SPLIT); 1768219089Spjd 1769219089Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1770219089Spjd return (error); 1771219089Spjd 1772219089Spjd if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1773219089Spjd zc->zc_iflags, &config)) { 1774219089Spjd spa_close(spa, FTAG); 1775219089Spjd return (error); 1776219089Spjd } 1777219089Spjd 1778219089Spjd if (zc->zc_nvlist_src_size != 0 && (error = 1779219089Spjd get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1780219089Spjd zc->zc_iflags, &props))) { 1781219089Spjd spa_close(spa, FTAG); 1782219089Spjd nvlist_free(config); 1783219089Spjd return (error); 1784219089Spjd } 1785219089Spjd 1786219089Spjd error = spa_vdev_split_mirror(spa, zc->zc_string, config, props, exp); 1787219089Spjd 1788219089Spjd spa_close(spa, FTAG); 1789219089Spjd 1790219089Spjd nvlist_free(config); 1791219089Spjd nvlist_free(props); 1792219089Spjd 1793219089Spjd return (error); 1794219089Spjd} 1795219089Spjd 1796219089Spjdstatic int 1797168404Spjdzfs_ioc_vdev_setpath(zfs_cmd_t *zc) 1798168404Spjd{ 1799168404Spjd spa_t *spa; 1800168404Spjd char *path = zc->zc_value; 1801168404Spjd uint64_t guid = zc->zc_guid; 1802168404Spjd int error; 1803168404Spjd 1804168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 1805168404Spjd if (error != 0) 1806168404Spjd return (error); 1807168404Spjd 1808168404Spjd error = spa_vdev_setpath(spa, guid, path); 1809168404Spjd spa_close(spa, FTAG); 1810168404Spjd return (error); 1811168404Spjd} 1812168404Spjd 1813209962Smmstatic int 1814209962Smmzfs_ioc_vdev_setfru(zfs_cmd_t *zc) 1815209962Smm{ 1816209962Smm spa_t *spa; 1817209962Smm char *fru = zc->zc_value; 1818209962Smm uint64_t guid = zc->zc_guid; 1819209962Smm int error; 1820209962Smm 1821209962Smm error = spa_open(zc->zc_name, &spa, FTAG); 1822209962Smm if (error != 0) 1823209962Smm return (error); 1824209962Smm 1825209962Smm error = spa_vdev_setfru(spa, guid, fru); 1826209962Smm spa_close(spa, FTAG); 1827209962Smm return (error); 1828209962Smm} 1829209962Smm 1830219089Spjdstatic int 1831219089Spjdzfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) 1832219089Spjd{ 1833219089Spjd int error = 0; 1834219089Spjd nvlist_t *nv; 1835219089Spjd 1836219089Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1837219089Spjd 1838219089Spjd if (zc->zc_nvlist_dst != 0 && 1839219089Spjd (error = dsl_prop_get_all(os, &nv)) == 0) { 1840219089Spjd dmu_objset_stats(os, nv); 1841219089Spjd /* 1842219089Spjd * NB: zvol_get_stats() will read the objset contents, 1843219089Spjd * which we aren't supposed to do with a 1844219089Spjd * DS_MODE_USER hold, because it could be 1845219089Spjd * inconsistent. So this is a bit of a workaround... 1846219089Spjd * XXX reading with out owning 1847219089Spjd */ 1848228103Smm if (!zc->zc_objset_stats.dds_inconsistent && 1849228103Smm dmu_objset_type(os) == DMU_OST_ZVOL) { 1850228103Smm error = zvol_get_stats(os, nv); 1851228103Smm if (error == EIO) 1852228103Smm return (error); 1853240415Smm VERIFY0(error); 1854219089Spjd } 1855219089Spjd error = put_nvlist(zc, nv); 1856219089Spjd nvlist_free(nv); 1857219089Spjd } 1858219089Spjd 1859219089Spjd return (error); 1860219089Spjd} 1861219089Spjd 1862185029Spjd/* 1863185029Spjd * inputs: 1864185029Spjd * zc_name name of filesystem 1865185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1866185029Spjd * 1867185029Spjd * outputs: 1868185029Spjd * zc_objset_stats stats 1869185029Spjd * zc_nvlist_dst property nvlist 1870185029Spjd * zc_nvlist_dst_size size of property nvlist 1871185029Spjd */ 1872168404Spjdstatic int 1873168404Spjdzfs_ioc_objset_stats(zfs_cmd_t *zc) 1874168404Spjd{ 1875168404Spjd objset_t *os = NULL; 1876168404Spjd int error; 1877219089Spjd 1878219089Spjd if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1879219089Spjd return (error); 1880219089Spjd 1881219089Spjd error = zfs_ioc_objset_stats_impl(zc, os); 1882219089Spjd 1883219089Spjd dmu_objset_rele(os, FTAG); 1884219089Spjd 1885219089Spjd if (error == ENOMEM) 1886219089Spjd error = 0; 1887219089Spjd return (error); 1888219089Spjd} 1889219089Spjd 1890219089Spjd/* 1891219089Spjd * inputs: 1892219089Spjd * zc_name name of filesystem 1893219089Spjd * zc_nvlist_dst_size size of buffer for property nvlist 1894219089Spjd * 1895219089Spjd * outputs: 1896219089Spjd * zc_nvlist_dst received property nvlist 1897219089Spjd * zc_nvlist_dst_size size of received property nvlist 1898219089Spjd * 1899219089Spjd * Gets received properties (distinct from local properties on or after 1900219089Spjd * SPA_VERSION_RECVD_PROPS) for callers who want to differentiate received from 1901219089Spjd * local property values. 1902219089Spjd */ 1903219089Spjdstatic int 1904219089Spjdzfs_ioc_objset_recvd_props(zfs_cmd_t *zc) 1905219089Spjd{ 1906219089Spjd objset_t *os = NULL; 1907219089Spjd int error; 1908168404Spjd nvlist_t *nv; 1909168404Spjd 1910219089Spjd if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1911168404Spjd return (error); 1912168404Spjd 1913219089Spjd /* 1914219089Spjd * Without this check, we would return local property values if the 1915219089Spjd * caller has not already received properties on or after 1916219089Spjd * SPA_VERSION_RECVD_PROPS. 1917219089Spjd */ 1918219089Spjd if (!dsl_prop_get_hasrecvd(os)) { 1919219089Spjd dmu_objset_rele(os, FTAG); 1920219089Spjd return (ENOTSUP); 1921219089Spjd } 1922168404Spjd 1923168404Spjd if (zc->zc_nvlist_dst != 0 && 1924219089Spjd (error = dsl_prop_get_received(os, &nv)) == 0) { 1925168404Spjd error = put_nvlist(zc, nv); 1926168404Spjd nvlist_free(nv); 1927168404Spjd } 1928168404Spjd 1929219089Spjd dmu_objset_rele(os, FTAG); 1930168404Spjd return (error); 1931168404Spjd} 1932168404Spjd 1933168404Spjdstatic int 1934185029Spjdnvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 1935185029Spjd{ 1936185029Spjd uint64_t value; 1937185029Spjd int error; 1938185029Spjd 1939185029Spjd /* 1940185029Spjd * zfs_get_zplprop() will either find a value or give us 1941185029Spjd * the default value (if there is one). 1942185029Spjd */ 1943185029Spjd if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 1944185029Spjd return (error); 1945185029Spjd VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 1946185029Spjd return (0); 1947185029Spjd} 1948185029Spjd 1949185029Spjd/* 1950185029Spjd * inputs: 1951185029Spjd * zc_name name of filesystem 1952185029Spjd * zc_nvlist_dst_size size of buffer for zpl property nvlist 1953185029Spjd * 1954185029Spjd * outputs: 1955185029Spjd * zc_nvlist_dst zpl property nvlist 1956185029Spjd * zc_nvlist_dst_size size of zpl property nvlist 1957185029Spjd */ 1958185029Spjdstatic int 1959185029Spjdzfs_ioc_objset_zplprops(zfs_cmd_t *zc) 1960185029Spjd{ 1961185029Spjd objset_t *os; 1962185029Spjd int err; 1963185029Spjd 1964219089Spjd /* XXX reading without owning */ 1965219089Spjd if (err = dmu_objset_hold(zc->zc_name, FTAG, &os)) 1966185029Spjd return (err); 1967185029Spjd 1968185029Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 1969185029Spjd 1970185029Spjd /* 1971185029Spjd * NB: nvl_add_zplprop() will read the objset contents, 1972185029Spjd * which we aren't supposed to do with a DS_MODE_USER 1973185029Spjd * hold, because it could be inconsistent. 1974185029Spjd */ 1975185029Spjd if (zc->zc_nvlist_dst != 0 && 1976185029Spjd !zc->zc_objset_stats.dds_inconsistent && 1977185029Spjd dmu_objset_type(os) == DMU_OST_ZFS) { 1978185029Spjd nvlist_t *nv; 1979185029Spjd 1980185029Spjd VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1981185029Spjd if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 1982185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 1983185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 1984185029Spjd (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 1985185029Spjd err = put_nvlist(zc, nv); 1986185029Spjd nvlist_free(nv); 1987185029Spjd } else { 1988185029Spjd err = ENOENT; 1989185029Spjd } 1990219089Spjd dmu_objset_rele(os, FTAG); 1991185029Spjd return (err); 1992185029Spjd} 1993185029Spjd 1994219089Spjdboolean_t 1995209962Smmdataset_name_hidden(const char *name) 1996209962Smm{ 1997209962Smm /* 1998209962Smm * Skip over datasets that are not visible in this zone, 1999209962Smm * internal datasets (which have a $ in their name), and 2000209962Smm * temporary datasets (which have a % in their name). 2001209962Smm */ 2002209962Smm if (strchr(name, '$') != NULL) 2003209962Smm return (B_TRUE); 2004209962Smm if (strchr(name, '%') != NULL) 2005209962Smm return (B_TRUE); 2006209962Smm if (!INGLOBALZONE(curthread) && !zone_dataset_visible(name, NULL)) 2007209962Smm return (B_TRUE); 2008209962Smm return (B_FALSE); 2009209962Smm} 2010209962Smm 2011185029Spjd/* 2012185029Spjd * inputs: 2013185029Spjd * zc_name name of filesystem 2014185029Spjd * zc_cookie zap cursor 2015185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 2016185029Spjd * 2017185029Spjd * outputs: 2018185029Spjd * zc_name name of next filesystem 2019209962Smm * zc_cookie zap cursor 2020185029Spjd * zc_objset_stats stats 2021185029Spjd * zc_nvlist_dst property nvlist 2022185029Spjd * zc_nvlist_dst_size size of property nvlist 2023185029Spjd */ 2024185029Spjdstatic int 2025168404Spjdzfs_ioc_dataset_list_next(zfs_cmd_t *zc) 2026168404Spjd{ 2027168404Spjd objset_t *os; 2028168404Spjd int error; 2029168404Spjd char *p; 2030219089Spjd size_t orig_len = strlen(zc->zc_name); 2031168404Spjd 2032219089Spjdtop: 2033219089Spjd if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) { 2034168404Spjd if (error == ENOENT) 2035168404Spjd error = ESRCH; 2036168404Spjd return (error); 2037168404Spjd } 2038168404Spjd 2039168404Spjd p = strrchr(zc->zc_name, '/'); 2040168404Spjd if (p == NULL || p[1] != '\0') 2041168404Spjd (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 2042168404Spjd p = zc->zc_name + strlen(zc->zc_name); 2043168404Spjd 2044209962Smm /* 2045209962Smm * Pre-fetch the datasets. dmu_objset_prefetch() always returns 0 2046209962Smm * but is not declared void because its called by dmu_objset_find(). 2047209962Smm */ 2048207626Smm if (zc->zc_cookie == 0) { 2049207626Smm uint64_t cookie = 0; 2050207626Smm int len = sizeof (zc->zc_name) - (p - zc->zc_name); 2051207626Smm 2052224855Smm while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) { 2053224855Smm if (!dataset_name_hidden(zc->zc_name)) 2054224814Smm (void) dmu_objset_prefetch(zc->zc_name, NULL); 2055224855Smm } 2056207626Smm } 2057207626Smm 2058168404Spjd do { 2059168404Spjd error = dmu_dir_list_next(os, 2060168404Spjd sizeof (zc->zc_name) - (p - zc->zc_name), p, 2061168404Spjd NULL, &zc->zc_cookie); 2062168404Spjd if (error == ENOENT) 2063168404Spjd error = ESRCH; 2064228103Smm } while (error == 0 && dataset_name_hidden(zc->zc_name)); 2065219089Spjd dmu_objset_rele(os, FTAG); 2066168404Spjd 2067219089Spjd /* 2068219089Spjd * If it's an internal dataset (ie. with a '$' in its name), 2069219089Spjd * don't try to get stats for it, otherwise we'll return ENOENT. 2070219089Spjd */ 2071219089Spjd if (error == 0 && strchr(zc->zc_name, '$') == NULL) { 2072168404Spjd error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 2073219089Spjd if (error == ENOENT) { 2074219089Spjd /* We lost a race with destroy, get the next one. */ 2075219089Spjd zc->zc_name[orig_len] = '\0'; 2076219089Spjd goto top; 2077219089Spjd } 2078219089Spjd } 2079168404Spjd return (error); 2080168404Spjd} 2081168404Spjd 2082185029Spjd/* 2083185029Spjd * inputs: 2084185029Spjd * zc_name name of filesystem 2085185029Spjd * zc_cookie zap cursor 2086185029Spjd * zc_nvlist_dst_size size of buffer for property nvlist 2087230438Spjd * zc_simple when set, only name is requested 2088185029Spjd * 2089185029Spjd * outputs: 2090185029Spjd * zc_name name of next snapshot 2091185029Spjd * zc_objset_stats stats 2092185029Spjd * zc_nvlist_dst property nvlist 2093185029Spjd * zc_nvlist_dst_size size of property nvlist 2094185029Spjd */ 2095168404Spjdstatic int 2096168404Spjdzfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 2097168404Spjd{ 2098168404Spjd objset_t *os; 2099168404Spjd int error; 2100168404Spjd 2101219089Spjdtop: 2102230438Spjd if (snapshot_list_prefetch && zc->zc_cookie == 0 && !zc->zc_simple) 2103219089Spjd (void) dmu_objset_find(zc->zc_name, dmu_objset_prefetch, 2104219089Spjd NULL, DS_FIND_SNAPSHOTS); 2105219089Spjd 2106219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &os); 2107185029Spjd if (error) 2108185029Spjd return (error == ENOENT ? ESRCH : error); 2109168404Spjd 2110168404Spjd /* 2111168404Spjd * A dataset name of maximum length cannot have any snapshots, 2112168404Spjd * so exit immediately. 2113168404Spjd */ 2114168404Spjd if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 2115219089Spjd dmu_objset_rele(os, FTAG); 2116168404Spjd return (ESRCH); 2117168404Spjd } 2118168404Spjd 2119168404Spjd error = dmu_snapshot_list_next(os, 2120168404Spjd sizeof (zc->zc_name) - strlen(zc->zc_name), 2121219089Spjd zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie, 2122219089Spjd NULL); 2123219089Spjd 2124230438Spjd if (error == 0 && !zc->zc_simple) { 2125219089Spjd dsl_dataset_t *ds; 2126219089Spjd dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool; 2127219089Spjd 2128219089Spjd /* 2129219089Spjd * Since we probably don't have a hold on this snapshot, 2130219089Spjd * it's possible that the objsetid could have been destroyed 2131219089Spjd * and reused for a new objset. It's OK if this happens during 2132219089Spjd * a zfs send operation, since the new createtxg will be 2133219089Spjd * beyond the range we're interested in. 2134219089Spjd */ 2135219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 2136219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds); 2137219089Spjd rw_exit(&dp->dp_config_rwlock); 2138219089Spjd if (error) { 2139219089Spjd if (error == ENOENT) { 2140219089Spjd /* Racing with destroy, get the next one. */ 2141219089Spjd *strchr(zc->zc_name, '@') = '\0'; 2142219089Spjd dmu_objset_rele(os, FTAG); 2143219089Spjd goto top; 2144219089Spjd } 2145219089Spjd } else { 2146219089Spjd objset_t *ossnap; 2147219089Spjd 2148219089Spjd error = dmu_objset_from_ds(ds, &ossnap); 2149219089Spjd if (error == 0) 2150219089Spjd error = zfs_ioc_objset_stats_impl(zc, ossnap); 2151219089Spjd dsl_dataset_rele(ds, FTAG); 2152219089Spjd } 2153219089Spjd } else if (error == ENOENT) { 2154185029Spjd error = ESRCH; 2155219089Spjd } 2156168404Spjd 2157219089Spjd dmu_objset_rele(os, FTAG); 2158185029Spjd /* if we failed, undo the @ that we tacked on to zc_name */ 2159185029Spjd if (error) 2160185029Spjd *strchr(zc->zc_name, '@') = '\0'; 2161168404Spjd return (error); 2162168404Spjd} 2163168404Spjd 2164219089Spjdstatic int 2165219089Spjdzfs_prop_set_userquota(const char *dsname, nvpair_t *pair) 2166168404Spjd{ 2167219089Spjd const char *propname = nvpair_name(pair); 2168219089Spjd uint64_t *valary; 2169219089Spjd unsigned int vallen; 2170219089Spjd const char *domain; 2171219089Spjd char *dash; 2172219089Spjd zfs_userquota_prop_t type; 2173219089Spjd uint64_t rid; 2174219089Spjd uint64_t quota; 2175219089Spjd zfsvfs_t *zfsvfs; 2176219089Spjd int err; 2177168404Spjd 2178219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2179219089Spjd nvlist_t *attrs; 2180219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2181219089Spjd if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2182219089Spjd &pair) != 0) 2183219089Spjd return (EINVAL); 2184219089Spjd } 2185219089Spjd 2186185029Spjd /* 2187219089Spjd * A correctly constructed propname is encoded as 2188219089Spjd * userquota@<rid>-<domain>. 2189185029Spjd */ 2190219089Spjd if ((dash = strchr(propname, '-')) == NULL || 2191219089Spjd nvpair_value_uint64_array(pair, &valary, &vallen) != 0 || 2192219089Spjd vallen != 3) 2193219089Spjd return (EINVAL); 2194168404Spjd 2195219089Spjd domain = dash + 1; 2196219089Spjd type = valary[0]; 2197219089Spjd rid = valary[1]; 2198219089Spjd quota = valary[2]; 2199168404Spjd 2200219089Spjd err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_FALSE); 2201219089Spjd if (err == 0) { 2202219089Spjd err = zfs_set_userquota(zfsvfs, type, domain, rid, quota); 2203219089Spjd zfsvfs_rele(zfsvfs, FTAG); 2204219089Spjd } 2205209962Smm 2206219089Spjd return (err); 2207219089Spjd} 2208168404Spjd 2209219089Spjd/* 2210219089Spjd * If the named property is one that has a special function to set its value, 2211219089Spjd * return 0 on success and a positive error code on failure; otherwise if it is 2212219089Spjd * not one of the special properties handled by this function, return -1. 2213219089Spjd * 2214219089Spjd * XXX: It would be better for callers of the property interface if we handled 2215219089Spjd * these special cases in dsl_prop.c (in the dsl layer). 2216219089Spjd */ 2217219089Spjdstatic int 2218219089Spjdzfs_prop_set_special(const char *dsname, zprop_source_t source, 2219219089Spjd nvpair_t *pair) 2220219089Spjd{ 2221219089Spjd const char *propname = nvpair_name(pair); 2222219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 2223219089Spjd uint64_t intval; 2224219089Spjd int err; 2225209962Smm 2226219089Spjd if (prop == ZPROP_INVAL) { 2227219089Spjd if (zfs_prop_userquota(propname)) 2228219089Spjd return (zfs_prop_set_userquota(dsname, pair)); 2229219089Spjd return (-1); 2230219089Spjd } 2231185029Spjd 2232219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2233219089Spjd nvlist_t *attrs; 2234219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2235219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2236219089Spjd &pair) == 0); 2237219089Spjd } 2238168404Spjd 2239219089Spjd if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) 2240219089Spjd return (-1); 2241185029Spjd 2242219089Spjd VERIFY(0 == nvpair_value_uint64(pair, &intval)); 2243185029Spjd 2244219089Spjd switch (prop) { 2245219089Spjd case ZFS_PROP_QUOTA: 2246219089Spjd err = dsl_dir_set_quota(dsname, source, intval); 2247219089Spjd break; 2248219089Spjd case ZFS_PROP_REFQUOTA: 2249219089Spjd err = dsl_dataset_set_quota(dsname, source, intval); 2250219089Spjd break; 2251219089Spjd case ZFS_PROP_RESERVATION: 2252219089Spjd err = dsl_dir_set_reservation(dsname, source, intval); 2253219089Spjd break; 2254219089Spjd case ZFS_PROP_REFRESERVATION: 2255219089Spjd err = dsl_dataset_set_reservation(dsname, source, intval); 2256219089Spjd break; 2257219089Spjd case ZFS_PROP_VOLSIZE: 2258219089Spjd err = zvol_set_volsize(dsname, ddi_driver_major(zfs_dip), 2259219089Spjd intval); 2260219089Spjd break; 2261219089Spjd case ZFS_PROP_VERSION: 2262219089Spjd { 2263219089Spjd zfsvfs_t *zfsvfs; 2264219089Spjd 2265219089Spjd if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) 2266185029Spjd break; 2267201143Sdelphij 2268219089Spjd err = zfs_set_version(zfsvfs, intval); 2269219089Spjd zfsvfs_rele(zfsvfs, FTAG); 2270168404Spjd 2271219089Spjd if (err == 0 && intval >= ZPL_VERSION_USERSPACE) { 2272219089Spjd zfs_cmd_t *zc; 2273185029Spjd 2274219089Spjd zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2275219089Spjd (void) strcpy(zc->zc_name, dsname); 2276219089Spjd (void) zfs_ioc_userspace_upgrade(zc); 2277219089Spjd kmem_free(zc, sizeof (zfs_cmd_t)); 2278185029Spjd } 2279219089Spjd break; 2280219089Spjd } 2281246586Sdelphij case ZFS_PROP_COMPRESSION: 2282246586Sdelphij { 2283246586Sdelphij if (intval == ZIO_COMPRESS_LZ4) { 2284246586Sdelphij zfeature_info_t *feature = 2285246586Sdelphij &spa_feature_table[SPA_FEATURE_LZ4_COMPRESS]; 2286246586Sdelphij spa_t *spa; 2287246586Sdelphij dsl_pool_t *dp; 2288185029Spjd 2289246586Sdelphij if ((err = spa_open(dsname, &spa, FTAG)) != 0) 2290246586Sdelphij return (err); 2291246586Sdelphij 2292246586Sdelphij dp = spa->spa_dsl_pool; 2293246586Sdelphij 2294246586Sdelphij /* 2295246586Sdelphij * Setting the LZ4 compression algorithm activates 2296246586Sdelphij * the feature. 2297246586Sdelphij */ 2298246586Sdelphij if (!spa_feature_is_active(spa, feature)) { 2299246586Sdelphij if ((err = zfs_prop_activate_feature(dp, 2300246586Sdelphij feature)) != 0) { 2301246586Sdelphij spa_close(spa, FTAG); 2302246586Sdelphij return (err); 2303246586Sdelphij } 2304246586Sdelphij } 2305246586Sdelphij 2306246586Sdelphij spa_close(spa, FTAG); 2307246586Sdelphij } 2308246586Sdelphij /* 2309246586Sdelphij * We still want the default set action to be performed in the 2310246586Sdelphij * caller, we only performed zfeature settings here. 2311246586Sdelphij */ 2312246586Sdelphij err = -1; 2313246586Sdelphij break; 2314246586Sdelphij } 2315246586Sdelphij 2316219089Spjd default: 2317219089Spjd err = -1; 2318219089Spjd } 2319168404Spjd 2320219089Spjd return (err); 2321219089Spjd} 2322185029Spjd 2323219089Spjd/* 2324219089Spjd * This function is best effort. If it fails to set any of the given properties, 2325219089Spjd * it continues to set as many as it can and returns the first error 2326219089Spjd * encountered. If the caller provides a non-NULL errlist, it also gives the 2327219089Spjd * complete list of names of all the properties it failed to set along with the 2328219089Spjd * corresponding error numbers. The caller is responsible for freeing the 2329219089Spjd * returned errlist. 2330219089Spjd * 2331219089Spjd * If every property is set successfully, zero is returned and the list pointed 2332219089Spjd * at by errlist is NULL. 2333219089Spjd */ 2334219089Spjdint 2335219089Spjdzfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, 2336219089Spjd nvlist_t **errlist) 2337219089Spjd{ 2338219089Spjd nvpair_t *pair; 2339219089Spjd nvpair_t *propval; 2340219089Spjd int rv = 0; 2341219089Spjd uint64_t intval; 2342219089Spjd char *strval; 2343219089Spjd nvlist_t *genericnvl; 2344219089Spjd nvlist_t *errors; 2345219089Spjd nvlist_t *retrynvl; 2346168404Spjd 2347219089Spjd VERIFY(nvlist_alloc(&genericnvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2348219089Spjd VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2349219089Spjd VERIFY(nvlist_alloc(&retrynvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2350168404Spjd 2351219089Spjdretry: 2352219089Spjd pair = NULL; 2353219089Spjd while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 2354219089Spjd const char *propname = nvpair_name(pair); 2355219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 2356219089Spjd int err = 0; 2357185029Spjd 2358219089Spjd /* decode the property value */ 2359219089Spjd propval = pair; 2360219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2361219089Spjd nvlist_t *attrs; 2362219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2363219089Spjd if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2364219089Spjd &propval) != 0) 2365219089Spjd err = EINVAL; 2366219089Spjd } 2367168404Spjd 2368219089Spjd /* Validate value type */ 2369219089Spjd if (err == 0 && prop == ZPROP_INVAL) { 2370219089Spjd if (zfs_prop_user(propname)) { 2371219089Spjd if (nvpair_type(propval) != DATA_TYPE_STRING) 2372219089Spjd err = EINVAL; 2373219089Spjd } else if (zfs_prop_userquota(propname)) { 2374219089Spjd if (nvpair_type(propval) != 2375219089Spjd DATA_TYPE_UINT64_ARRAY) 2376219089Spjd err = EINVAL; 2377228103Smm } else { 2378228103Smm err = EINVAL; 2379209962Smm } 2380219089Spjd } else if (err == 0) { 2381219089Spjd if (nvpair_type(propval) == DATA_TYPE_STRING) { 2382219089Spjd if (zfs_prop_get_type(prop) != PROP_TYPE_STRING) 2383219089Spjd err = EINVAL; 2384219089Spjd } else if (nvpair_type(propval) == DATA_TYPE_UINT64) { 2385168404Spjd const char *unused; 2386168404Spjd 2387219089Spjd VERIFY(nvpair_value_uint64(propval, 2388219089Spjd &intval) == 0); 2389168404Spjd 2390168404Spjd switch (zfs_prop_get_type(prop)) { 2391185029Spjd case PROP_TYPE_NUMBER: 2392168404Spjd break; 2393185029Spjd case PROP_TYPE_STRING: 2394219089Spjd err = EINVAL; 2395219089Spjd break; 2396185029Spjd case PROP_TYPE_INDEX: 2397168404Spjd if (zfs_prop_index_to_string(prop, 2398219089Spjd intval, &unused) != 0) 2399219089Spjd err = EINVAL; 2400168404Spjd break; 2401168404Spjd default: 2402185029Spjd cmn_err(CE_PANIC, 2403185029Spjd "unknown property type"); 2404168404Spjd } 2405168404Spjd } else { 2406219089Spjd err = EINVAL; 2407168404Spjd } 2408168404Spjd } 2409219089Spjd 2410219089Spjd /* Validate permissions */ 2411219089Spjd if (err == 0) 2412219089Spjd err = zfs_check_settable(dsname, pair, CRED()); 2413219089Spjd 2414219089Spjd if (err == 0) { 2415219089Spjd err = zfs_prop_set_special(dsname, source, pair); 2416219089Spjd if (err == -1) { 2417219089Spjd /* 2418219089Spjd * For better performance we build up a list of 2419219089Spjd * properties to set in a single transaction. 2420219089Spjd */ 2421219089Spjd err = nvlist_add_nvpair(genericnvl, pair); 2422219089Spjd } else if (err != 0 && nvl != retrynvl) { 2423219089Spjd /* 2424219089Spjd * This may be a spurious error caused by 2425219089Spjd * receiving quota and reservation out of order. 2426219089Spjd * Try again in a second pass. 2427219089Spjd */ 2428219089Spjd err = nvlist_add_nvpair(retrynvl, pair); 2429219089Spjd } 2430219089Spjd } 2431219089Spjd 2432219089Spjd if (err != 0) 2433219089Spjd VERIFY(nvlist_add_int32(errors, propname, err) == 0); 2434168404Spjd } 2435168404Spjd 2436219089Spjd if (nvl != retrynvl && !nvlist_empty(retrynvl)) { 2437219089Spjd nvl = retrynvl; 2438219089Spjd goto retry; 2439209962Smm } 2440219089Spjd 2441219089Spjd if (!nvlist_empty(genericnvl) && 2442219089Spjd dsl_props_set(dsname, source, genericnvl) != 0) { 2443219089Spjd /* 2444219089Spjd * If this fails, we still want to set as many properties as we 2445219089Spjd * can, so try setting them individually. 2446219089Spjd */ 2447219089Spjd pair = NULL; 2448219089Spjd while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) { 2449219089Spjd const char *propname = nvpair_name(pair); 2450219089Spjd int err = 0; 2451219089Spjd 2452219089Spjd propval = pair; 2453219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 2454219089Spjd nvlist_t *attrs; 2455219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2456219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2457219089Spjd &propval) == 0); 2458219089Spjd } 2459219089Spjd 2460219089Spjd if (nvpair_type(propval) == DATA_TYPE_STRING) { 2461219089Spjd VERIFY(nvpair_value_string(propval, 2462219089Spjd &strval) == 0); 2463219089Spjd err = dsl_prop_set(dsname, propname, source, 1, 2464219089Spjd strlen(strval) + 1, strval); 2465219089Spjd } else { 2466219089Spjd VERIFY(nvpair_value_uint64(propval, 2467219089Spjd &intval) == 0); 2468219089Spjd err = dsl_prop_set(dsname, propname, source, 8, 2469219089Spjd 1, &intval); 2470219089Spjd } 2471219089Spjd 2472219089Spjd if (err != 0) { 2473219089Spjd VERIFY(nvlist_add_int32(errors, propname, 2474219089Spjd err) == 0); 2475219089Spjd } 2476219089Spjd } 2477219089Spjd } 2478209962Smm nvlist_free(genericnvl); 2479219089Spjd nvlist_free(retrynvl); 2480219089Spjd 2481219089Spjd if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) { 2482219089Spjd nvlist_free(errors); 2483219089Spjd errors = NULL; 2484219089Spjd } else { 2485219089Spjd VERIFY(nvpair_value_int32(pair, &rv) == 0); 2486219089Spjd } 2487219089Spjd 2488219089Spjd if (errlist == NULL) 2489219089Spjd nvlist_free(errors); 2490219089Spjd else 2491219089Spjd *errlist = errors; 2492219089Spjd 2493219089Spjd return (rv); 2494209962Smm} 2495209962Smm 2496209962Smm/* 2497209962Smm * Check that all the properties are valid user properties. 2498209962Smm */ 2499209962Smmstatic int 2500209962Smmzfs_check_userprops(char *fsname, nvlist_t *nvl) 2501209962Smm{ 2502219089Spjd nvpair_t *pair = NULL; 2503209962Smm int error = 0; 2504209962Smm 2505219089Spjd while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 2506219089Spjd const char *propname = nvpair_name(pair); 2507209962Smm char *valstr; 2508209962Smm 2509209962Smm if (!zfs_prop_user(propname) || 2510219089Spjd nvpair_type(pair) != DATA_TYPE_STRING) 2511209962Smm return (EINVAL); 2512209962Smm 2513209962Smm if (error = zfs_secpolicy_write_perms(fsname, 2514209962Smm ZFS_DELEG_PERM_USERPROP, CRED())) 2515209962Smm return (error); 2516209962Smm 2517209962Smm if (strlen(propname) >= ZAP_MAXNAMELEN) 2518209962Smm return (ENAMETOOLONG); 2519209962Smm 2520219089Spjd VERIFY(nvpair_value_string(pair, &valstr) == 0); 2521209962Smm if (strlen(valstr) >= ZAP_MAXVALUELEN) 2522209962Smm return (E2BIG); 2523209962Smm } 2524168404Spjd return (0); 2525168404Spjd} 2526168404Spjd 2527219089Spjdstatic void 2528219089Spjdprops_skip(nvlist_t *props, nvlist_t *skipped, nvlist_t **newprops) 2529219089Spjd{ 2530219089Spjd nvpair_t *pair; 2531219089Spjd 2532219089Spjd VERIFY(nvlist_alloc(newprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2533219089Spjd 2534219089Spjd pair = NULL; 2535219089Spjd while ((pair = nvlist_next_nvpair(props, pair)) != NULL) { 2536219089Spjd if (nvlist_exists(skipped, nvpair_name(pair))) 2537219089Spjd continue; 2538219089Spjd 2539219089Spjd VERIFY(nvlist_add_nvpair(*newprops, pair) == 0); 2540219089Spjd } 2541219089Spjd} 2542219089Spjd 2543219089Spjdstatic int 2544219089Spjdclear_received_props(objset_t *os, const char *fs, nvlist_t *props, 2545219089Spjd nvlist_t *skipped) 2546219089Spjd{ 2547219089Spjd int err = 0; 2548219089Spjd nvlist_t *cleared_props = NULL; 2549219089Spjd props_skip(props, skipped, &cleared_props); 2550219089Spjd if (!nvlist_empty(cleared_props)) { 2551219089Spjd /* 2552219089Spjd * Acts on local properties until the dataset has received 2553219089Spjd * properties at least once on or after SPA_VERSION_RECVD_PROPS. 2554219089Spjd */ 2555219089Spjd zprop_source_t flags = (ZPROP_SRC_NONE | 2556219089Spjd (dsl_prop_get_hasrecvd(os) ? ZPROP_SRC_RECEIVED : 0)); 2557219089Spjd err = zfs_set_prop_nvlist(fs, flags, cleared_props, NULL); 2558219089Spjd } 2559219089Spjd nvlist_free(cleared_props); 2560219089Spjd return (err); 2561219089Spjd} 2562219089Spjd 2563185029Spjd/* 2564185029Spjd * inputs: 2565185029Spjd * zc_name name of filesystem 2566209962Smm * zc_value name of property to set 2567185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 2568219089Spjd * zc_cookie received properties flag 2569185029Spjd * 2570219089Spjd * outputs: 2571219089Spjd * zc_nvlist_dst{_size} error for each unapplied received property 2572185029Spjd */ 2573168404Spjdstatic int 2574168404Spjdzfs_ioc_set_prop(zfs_cmd_t *zc) 2575168404Spjd{ 2576168404Spjd nvlist_t *nvl; 2577219089Spjd boolean_t received = zc->zc_cookie; 2578219089Spjd zprop_source_t source = (received ? ZPROP_SRC_RECEIVED : 2579219089Spjd ZPROP_SRC_LOCAL); 2580219089Spjd nvlist_t *errors = NULL; 2581168404Spjd int error; 2582168404Spjd 2583185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2584219089Spjd zc->zc_iflags, &nvl)) != 0) 2585185029Spjd return (error); 2586168404Spjd 2587219089Spjd if (received) { 2588185029Spjd nvlist_t *origprops; 2589185029Spjd objset_t *os; 2590185029Spjd 2591219089Spjd if (dmu_objset_hold(zc->zc_name, FTAG, &os) == 0) { 2592219089Spjd if (dsl_prop_get_received(os, &origprops) == 0) { 2593219089Spjd (void) clear_received_props(os, 2594219089Spjd zc->zc_name, origprops, nvl); 2595185029Spjd nvlist_free(origprops); 2596185029Spjd } 2597219089Spjd 2598219089Spjd dsl_prop_set_hasrecvd(os); 2599219089Spjd dmu_objset_rele(os, FTAG); 2600185029Spjd } 2601219089Spjd } 2602185029Spjd 2603219089Spjd error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, &errors); 2604219089Spjd 2605219089Spjd if (zc->zc_nvlist_dst != 0 && errors != NULL) { 2606219089Spjd (void) put_nvlist(zc, errors); 2607168404Spjd } 2608168404Spjd 2609219089Spjd nvlist_free(errors); 2610168404Spjd nvlist_free(nvl); 2611168404Spjd return (error); 2612168404Spjd} 2613168404Spjd 2614185029Spjd/* 2615185029Spjd * inputs: 2616185029Spjd * zc_name name of filesystem 2617185029Spjd * zc_value name of property to inherit 2618219089Spjd * zc_cookie revert to received value if TRUE 2619185029Spjd * 2620185029Spjd * outputs: none 2621185029Spjd */ 2622168404Spjdstatic int 2623185029Spjdzfs_ioc_inherit_prop(zfs_cmd_t *zc) 2624185029Spjd{ 2625219089Spjd const char *propname = zc->zc_value; 2626219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 2627219089Spjd boolean_t received = zc->zc_cookie; 2628219089Spjd zprop_source_t source = (received 2629219089Spjd ? ZPROP_SRC_NONE /* revert to received value, if any */ 2630219089Spjd : ZPROP_SRC_INHERITED); /* explicitly inherit */ 2631219089Spjd 2632219089Spjd if (received) { 2633219089Spjd nvlist_t *dummy; 2634219089Spjd nvpair_t *pair; 2635219089Spjd zprop_type_t type; 2636219089Spjd int err; 2637219089Spjd 2638219089Spjd /* 2639219089Spjd * zfs_prop_set_special() expects properties in the form of an 2640219089Spjd * nvpair with type info. 2641219089Spjd */ 2642219089Spjd if (prop == ZPROP_INVAL) { 2643219089Spjd if (!zfs_prop_user(propname)) 2644219089Spjd return (EINVAL); 2645219089Spjd 2646219089Spjd type = PROP_TYPE_STRING; 2647219089Spjd } else if (prop == ZFS_PROP_VOLSIZE || 2648219089Spjd prop == ZFS_PROP_VERSION) { 2649219089Spjd return (EINVAL); 2650219089Spjd } else { 2651219089Spjd type = zfs_prop_get_type(prop); 2652219089Spjd } 2653219089Spjd 2654219089Spjd VERIFY(nvlist_alloc(&dummy, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2655219089Spjd 2656219089Spjd switch (type) { 2657219089Spjd case PROP_TYPE_STRING: 2658219089Spjd VERIFY(0 == nvlist_add_string(dummy, propname, "")); 2659219089Spjd break; 2660219089Spjd case PROP_TYPE_NUMBER: 2661219089Spjd case PROP_TYPE_INDEX: 2662219089Spjd VERIFY(0 == nvlist_add_uint64(dummy, propname, 0)); 2663219089Spjd break; 2664219089Spjd default: 2665219089Spjd nvlist_free(dummy); 2666219089Spjd return (EINVAL); 2667219089Spjd } 2668219089Spjd 2669219089Spjd pair = nvlist_next_nvpair(dummy, NULL); 2670219089Spjd err = zfs_prop_set_special(zc->zc_name, source, pair); 2671219089Spjd nvlist_free(dummy); 2672219089Spjd if (err != -1) 2673219089Spjd return (err); /* special property already handled */ 2674219089Spjd } else { 2675219089Spjd /* 2676219089Spjd * Only check this in the non-received case. We want to allow 2677219089Spjd * 'inherit -S' to revert non-inheritable properties like quota 2678219089Spjd * and reservation to the received or default values even though 2679219089Spjd * they are not considered inheritable. 2680219089Spjd */ 2681219089Spjd if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 2682219089Spjd return (EINVAL); 2683219089Spjd } 2684219089Spjd 2685185029Spjd /* the property name has been validated by zfs_secpolicy_inherit() */ 2686219089Spjd return (dsl_prop_set(zc->zc_name, zc->zc_value, source, 0, 0, NULL)); 2687185029Spjd} 2688185029Spjd 2689185029Spjdstatic int 2690169055Spjdzfs_ioc_pool_set_props(zfs_cmd_t *zc) 2691168404Spjd{ 2692185029Spjd nvlist_t *props; 2693168404Spjd spa_t *spa; 2694185029Spjd int error; 2695219089Spjd nvpair_t *pair; 2696168404Spjd 2697219089Spjd if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2698219089Spjd zc->zc_iflags, &props)) 2699168404Spjd return (error); 2700168404Spjd 2701209962Smm /* 2702209962Smm * If the only property is the configfile, then just do a spa_lookup() 2703209962Smm * to handle the faulted case. 2704209962Smm */ 2705219089Spjd pair = nvlist_next_nvpair(props, NULL); 2706219089Spjd if (pair != NULL && strcmp(nvpair_name(pair), 2707209962Smm zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 2708219089Spjd nvlist_next_nvpair(props, pair) == NULL) { 2709209962Smm mutex_enter(&spa_namespace_lock); 2710209962Smm if ((spa = spa_lookup(zc->zc_name)) != NULL) { 2711209962Smm spa_configfile_set(spa, props, B_FALSE); 2712209962Smm spa_config_sync(spa, B_FALSE, B_TRUE); 2713209962Smm } 2714209962Smm mutex_exit(&spa_namespace_lock); 2715219089Spjd if (spa != NULL) { 2716219089Spjd nvlist_free(props); 2717209962Smm return (0); 2718219089Spjd } 2719209962Smm } 2720209962Smm 2721168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2722185029Spjd nvlist_free(props); 2723168404Spjd return (error); 2724168404Spjd } 2725168404Spjd 2726185029Spjd error = spa_prop_set(spa, props); 2727168404Spjd 2728185029Spjd nvlist_free(props); 2729168404Spjd spa_close(spa, FTAG); 2730168404Spjd 2731168404Spjd return (error); 2732168404Spjd} 2733168404Spjd 2734168404Spjdstatic int 2735169055Spjdzfs_ioc_pool_get_props(zfs_cmd_t *zc) 2736168404Spjd{ 2737168404Spjd spa_t *spa; 2738168404Spjd int error; 2739168404Spjd nvlist_t *nvp = NULL; 2740168404Spjd 2741209962Smm if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2742209962Smm /* 2743209962Smm * If the pool is faulted, there may be properties we can still 2744209962Smm * get (such as altroot and cachefile), so attempt to get them 2745209962Smm * anyway. 2746209962Smm */ 2747209962Smm mutex_enter(&spa_namespace_lock); 2748209962Smm if ((spa = spa_lookup(zc->zc_name)) != NULL) 2749209962Smm error = spa_prop_get(spa, &nvp); 2750209962Smm mutex_exit(&spa_namespace_lock); 2751209962Smm } else { 2752209962Smm error = spa_prop_get(spa, &nvp); 2753209962Smm spa_close(spa, FTAG); 2754209962Smm } 2755168404Spjd 2756168404Spjd if (error == 0 && zc->zc_nvlist_dst != 0) 2757168404Spjd error = put_nvlist(zc, nvp); 2758168404Spjd else 2759168404Spjd error = EFAULT; 2760168404Spjd 2761209962Smm nvlist_free(nvp); 2762168404Spjd return (error); 2763168404Spjd} 2764168404Spjd 2765185029Spjd/* 2766185029Spjd * inputs: 2767185029Spjd * zc_name name of filesystem 2768185029Spjd * zc_nvlist_src{_size} nvlist of delegated permissions 2769185029Spjd * zc_perm_action allow/unallow flag 2770185029Spjd * 2771185029Spjd * outputs: none 2772185029Spjd */ 2773185029Spjdstatic int 2774185029Spjdzfs_ioc_set_fsacl(zfs_cmd_t *zc) 2775185029Spjd{ 2776185029Spjd int error; 2777185029Spjd nvlist_t *fsaclnv = NULL; 2778185029Spjd 2779185029Spjd if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2780219089Spjd zc->zc_iflags, &fsaclnv)) != 0) 2781185029Spjd return (error); 2782185029Spjd 2783185029Spjd /* 2784185029Spjd * Verify nvlist is constructed correctly 2785185029Spjd */ 2786185029Spjd if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 2787185029Spjd nvlist_free(fsaclnv); 2788185029Spjd return (EINVAL); 2789185029Spjd } 2790185029Spjd 2791185029Spjd /* 2792185029Spjd * If we don't have PRIV_SYS_MOUNT, then validate 2793185029Spjd * that user is allowed to hand out each permission in 2794185029Spjd * the nvlist(s) 2795185029Spjd */ 2796185029Spjd 2797185029Spjd error = secpolicy_zfs(CRED()); 2798185029Spjd if (error) { 2799185029Spjd if (zc->zc_perm_action == B_FALSE) { 2800185029Spjd error = dsl_deleg_can_allow(zc->zc_name, 2801185029Spjd fsaclnv, CRED()); 2802185029Spjd } else { 2803185029Spjd error = dsl_deleg_can_unallow(zc->zc_name, 2804185029Spjd fsaclnv, CRED()); 2805185029Spjd } 2806185029Spjd } 2807185029Spjd 2808185029Spjd if (error == 0) 2809185029Spjd error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 2810185029Spjd 2811185029Spjd nvlist_free(fsaclnv); 2812185029Spjd return (error); 2813185029Spjd} 2814185029Spjd 2815185029Spjd/* 2816185029Spjd * inputs: 2817185029Spjd * zc_name name of filesystem 2818185029Spjd * 2819185029Spjd * outputs: 2820185029Spjd * zc_nvlist_src{_size} nvlist of delegated permissions 2821185029Spjd */ 2822185029Spjdstatic int 2823185029Spjdzfs_ioc_get_fsacl(zfs_cmd_t *zc) 2824185029Spjd{ 2825185029Spjd nvlist_t *nvp; 2826185029Spjd int error; 2827185029Spjd 2828185029Spjd if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 2829185029Spjd error = put_nvlist(zc, nvp); 2830185029Spjd nvlist_free(nvp); 2831185029Spjd } 2832185029Spjd 2833185029Spjd return (error); 2834185029Spjd} 2835185029Spjd 2836185029Spjd/* 2837168404Spjd * Search the vfs list for a specified resource. Returns a pointer to it 2838168404Spjd * or NULL if no suitable entry is found. The caller of this routine 2839168404Spjd * is responsible for releasing the returned vfs pointer. 2840168404Spjd */ 2841168404Spjdstatic vfs_t * 2842168404Spjdzfs_get_vfs(const char *resource) 2843168404Spjd{ 2844168404Spjd vfs_t *vfsp; 2845168404Spjd 2846168404Spjd mtx_lock(&mountlist_mtx); 2847168404Spjd TAILQ_FOREACH(vfsp, &mountlist, mnt_list) { 2848185029Spjd if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { 2849168404Spjd VFS_HOLD(vfsp); 2850168404Spjd break; 2851168404Spjd } 2852168404Spjd } 2853168404Spjd mtx_unlock(&mountlist_mtx); 2854168404Spjd return (vfsp); 2855168404Spjd} 2856168404Spjd 2857185029Spjd/* ARGSUSED */ 2858168404Spjdstatic void 2859185029Spjdzfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 2860168404Spjd{ 2861185029Spjd zfs_creat_t *zct = arg; 2862168404Spjd 2863185029Spjd zfs_create_fs(os, cr, zct->zct_zplprops, tx); 2864168404Spjd} 2865168404Spjd 2866185029Spjd#define ZFS_PROP_UNDEFINED ((uint64_t)-1) 2867185029Spjd 2868185029Spjd/* 2869185029Spjd * inputs: 2870185029Spjd * createprops list of properties requested by creator 2871185029Spjd * default_zplver zpl version to use if unspecified in createprops 2872185029Spjd * fuids_ok fuids allowed in this version of the spa? 2873185029Spjd * os parent objset pointer (NULL if root fs) 2874185029Spjd * 2875185029Spjd * outputs: 2876185029Spjd * zplprops values for the zplprops we attach to the master node object 2877185029Spjd * is_ci true if requested file system will be purely case-insensitive 2878185029Spjd * 2879185029Spjd * Determine the settings for utf8only, normalization and 2880185029Spjd * casesensitivity. Specific values may have been requested by the 2881185029Spjd * creator and/or we can inherit values from the parent dataset. If 2882185029Spjd * the file system is of too early a vintage, a creator can not 2883185029Spjd * request settings for these properties, even if the requested 2884185029Spjd * setting is the default value. We don't actually want to create dsl 2885185029Spjd * properties for these, so remove them from the source nvlist after 2886185029Spjd * processing. 2887185029Spjd */ 2888168404Spjdstatic int 2889209962Smmzfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 2890219089Spjd boolean_t fuids_ok, boolean_t sa_ok, nvlist_t *createprops, 2891219089Spjd nvlist_t *zplprops, boolean_t *is_ci) 2892185029Spjd{ 2893185029Spjd uint64_t sense = ZFS_PROP_UNDEFINED; 2894185029Spjd uint64_t norm = ZFS_PROP_UNDEFINED; 2895185029Spjd uint64_t u8 = ZFS_PROP_UNDEFINED; 2896185029Spjd 2897185029Spjd ASSERT(zplprops != NULL); 2898185029Spjd 2899185029Spjd /* 2900185029Spjd * Pull out creator prop choices, if any. 2901185029Spjd */ 2902185029Spjd if (createprops) { 2903185029Spjd (void) nvlist_lookup_uint64(createprops, 2904185029Spjd zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 2905185029Spjd (void) nvlist_lookup_uint64(createprops, 2906185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 2907185029Spjd (void) nvlist_remove_all(createprops, 2908185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 2909185029Spjd (void) nvlist_lookup_uint64(createprops, 2910185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 2911185029Spjd (void) nvlist_remove_all(createprops, 2912185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 2913185029Spjd (void) nvlist_lookup_uint64(createprops, 2914185029Spjd zfs_prop_to_name(ZFS_PROP_CASE), &sense); 2915185029Spjd (void) nvlist_remove_all(createprops, 2916185029Spjd zfs_prop_to_name(ZFS_PROP_CASE)); 2917185029Spjd } 2918185029Spjd 2919185029Spjd /* 2920185029Spjd * If the zpl version requested is whacky or the file system 2921185029Spjd * or pool is version is too "young" to support normalization 2922185029Spjd * and the creator tried to set a value for one of the props, 2923185029Spjd * error out. 2924185029Spjd */ 2925185029Spjd if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 2926185029Spjd (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 2927219089Spjd (zplver >= ZPL_VERSION_SA && !sa_ok) || 2928185029Spjd (zplver < ZPL_VERSION_NORMALIZATION && 2929185029Spjd (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 2930185029Spjd sense != ZFS_PROP_UNDEFINED))) 2931185029Spjd return (ENOTSUP); 2932185029Spjd 2933185029Spjd /* 2934185029Spjd * Put the version in the zplprops 2935185029Spjd */ 2936185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2937185029Spjd zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 2938185029Spjd 2939185029Spjd if (norm == ZFS_PROP_UNDEFINED) 2940185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 2941185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2942185029Spjd zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 2943185029Spjd 2944185029Spjd /* 2945185029Spjd * If we're normalizing, names must always be valid UTF-8 strings. 2946185029Spjd */ 2947185029Spjd if (norm) 2948185029Spjd u8 = 1; 2949185029Spjd if (u8 == ZFS_PROP_UNDEFINED) 2950185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 2951185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2952185029Spjd zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 2953185029Spjd 2954185029Spjd if (sense == ZFS_PROP_UNDEFINED) 2955185029Spjd VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 2956185029Spjd VERIFY(nvlist_add_uint64(zplprops, 2957185029Spjd zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 2958185029Spjd 2959185029Spjd if (is_ci) 2960185029Spjd *is_ci = (sense == ZFS_CASE_INSENSITIVE); 2961185029Spjd 2962185029Spjd return (0); 2963185029Spjd} 2964185029Spjd 2965185029Spjdstatic int 2966185029Spjdzfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 2967185029Spjd nvlist_t *zplprops, boolean_t *is_ci) 2968185029Spjd{ 2969219089Spjd boolean_t fuids_ok, sa_ok; 2970185029Spjd uint64_t zplver = ZPL_VERSION; 2971185029Spjd objset_t *os = NULL; 2972185029Spjd char parentname[MAXNAMELEN]; 2973185029Spjd char *cp; 2974219089Spjd spa_t *spa; 2975219089Spjd uint64_t spa_vers; 2976185029Spjd int error; 2977185029Spjd 2978185029Spjd (void) strlcpy(parentname, dataset, sizeof (parentname)); 2979185029Spjd cp = strrchr(parentname, '/'); 2980185029Spjd ASSERT(cp != NULL); 2981185029Spjd cp[0] = '\0'; 2982185029Spjd 2983219089Spjd if ((error = spa_open(dataset, &spa, FTAG)) != 0) 2984219089Spjd return (error); 2985185029Spjd 2986219089Spjd spa_vers = spa_version(spa); 2987219089Spjd spa_close(spa, FTAG); 2988219089Spjd 2989219089Spjd zplver = zfs_zpl_version_map(spa_vers); 2990219089Spjd fuids_ok = (zplver >= ZPL_VERSION_FUID); 2991219089Spjd sa_ok = (zplver >= ZPL_VERSION_SA); 2992219089Spjd 2993185029Spjd /* 2994185029Spjd * Open parent object set so we can inherit zplprop values. 2995185029Spjd */ 2996219089Spjd if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0) 2997185029Spjd return (error); 2998185029Spjd 2999219089Spjd error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, sa_ok, createprops, 3000185029Spjd zplprops, is_ci); 3001219089Spjd dmu_objset_rele(os, FTAG); 3002185029Spjd return (error); 3003185029Spjd} 3004185029Spjd 3005185029Spjdstatic int 3006185029Spjdzfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 3007185029Spjd nvlist_t *zplprops, boolean_t *is_ci) 3008185029Spjd{ 3009219089Spjd boolean_t fuids_ok; 3010219089Spjd boolean_t sa_ok; 3011185029Spjd uint64_t zplver = ZPL_VERSION; 3012185029Spjd int error; 3013185029Spjd 3014219089Spjd zplver = zfs_zpl_version_map(spa_vers); 3015219089Spjd fuids_ok = (zplver >= ZPL_VERSION_FUID); 3016219089Spjd sa_ok = (zplver >= ZPL_VERSION_SA); 3017185029Spjd 3018219089Spjd error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, sa_ok, 3019219089Spjd createprops, zplprops, is_ci); 3020185029Spjd return (error); 3021185029Spjd} 3022185029Spjd 3023185029Spjd/* 3024185029Spjd * inputs: 3025185029Spjd * zc_objset_type type of objset to create (fs vs zvol) 3026185029Spjd * zc_name name of new objset 3027185029Spjd * zc_value name of snapshot to clone from (may be empty) 3028185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 3029185029Spjd * 3030185029Spjd * outputs: none 3031185029Spjd */ 3032185029Spjdstatic int 3033168404Spjdzfs_ioc_create(zfs_cmd_t *zc) 3034168404Spjd{ 3035168404Spjd objset_t *clone; 3036168404Spjd int error = 0; 3037185029Spjd zfs_creat_t zct; 3038185029Spjd nvlist_t *nvprops = NULL; 3039185029Spjd void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 3040168404Spjd dmu_objset_type_t type = zc->zc_objset_type; 3041168404Spjd 3042168404Spjd switch (type) { 3043168404Spjd 3044168404Spjd case DMU_OST_ZFS: 3045168404Spjd cbfunc = zfs_create_cb; 3046168404Spjd break; 3047168404Spjd 3048168404Spjd case DMU_OST_ZVOL: 3049168404Spjd cbfunc = zvol_create_cb; 3050168404Spjd break; 3051168404Spjd 3052168404Spjd default: 3053168404Spjd cbfunc = NULL; 3054185029Spjd break; 3055168404Spjd } 3056185029Spjd if (strchr(zc->zc_name, '@') || 3057185029Spjd strchr(zc->zc_name, '%')) 3058168404Spjd return (EINVAL); 3059168404Spjd 3060168404Spjd if (zc->zc_nvlist_src != 0 && 3061185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3062219089Spjd zc->zc_iflags, &nvprops)) != 0) 3063168404Spjd return (error); 3064168404Spjd 3065185029Spjd zct.zct_zplprops = NULL; 3066185029Spjd zct.zct_props = nvprops; 3067168404Spjd 3068168404Spjd if (zc->zc_value[0] != '\0') { 3069168404Spjd /* 3070168404Spjd * We're creating a clone of an existing snapshot. 3071168404Spjd */ 3072168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 3073168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 3074185029Spjd nvlist_free(nvprops); 3075168404Spjd return (EINVAL); 3076168404Spjd } 3077168404Spjd 3078219089Spjd error = dmu_objset_hold(zc->zc_value, FTAG, &clone); 3079168404Spjd if (error) { 3080185029Spjd nvlist_free(nvprops); 3081168404Spjd return (error); 3082168404Spjd } 3083185029Spjd 3084219089Spjd error = dmu_objset_clone(zc->zc_name, dmu_objset_ds(clone), 0); 3085219089Spjd dmu_objset_rele(clone, FTAG); 3086185029Spjd if (error) { 3087185029Spjd nvlist_free(nvprops); 3088185029Spjd return (error); 3089185029Spjd } 3090168404Spjd } else { 3091185029Spjd boolean_t is_insensitive = B_FALSE; 3092185029Spjd 3093168404Spjd if (cbfunc == NULL) { 3094185029Spjd nvlist_free(nvprops); 3095168404Spjd return (EINVAL); 3096168404Spjd } 3097168404Spjd 3098168404Spjd if (type == DMU_OST_ZVOL) { 3099168404Spjd uint64_t volsize, volblocksize; 3100168404Spjd 3101185029Spjd if (nvprops == NULL || 3102185029Spjd nvlist_lookup_uint64(nvprops, 3103168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 3104168404Spjd &volsize) != 0) { 3105185029Spjd nvlist_free(nvprops); 3106168404Spjd return (EINVAL); 3107168404Spjd } 3108168404Spjd 3109185029Spjd if ((error = nvlist_lookup_uint64(nvprops, 3110168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 3111168404Spjd &volblocksize)) != 0 && error != ENOENT) { 3112185029Spjd nvlist_free(nvprops); 3113168404Spjd return (EINVAL); 3114168404Spjd } 3115168404Spjd 3116168404Spjd if (error != 0) 3117168404Spjd volblocksize = zfs_prop_default_numeric( 3118168404Spjd ZFS_PROP_VOLBLOCKSIZE); 3119168404Spjd 3120168404Spjd if ((error = zvol_check_volblocksize( 3121168404Spjd volblocksize)) != 0 || 3122168404Spjd (error = zvol_check_volsize(volsize, 3123168404Spjd volblocksize)) != 0) { 3124185029Spjd nvlist_free(nvprops); 3125168404Spjd return (error); 3126168404Spjd } 3127185029Spjd } else if (type == DMU_OST_ZFS) { 3128185029Spjd int error; 3129185029Spjd 3130185029Spjd /* 3131185029Spjd * We have to have normalization and 3132185029Spjd * case-folding flags correct when we do the 3133185029Spjd * file system creation, so go figure them out 3134185029Spjd * now. 3135185029Spjd */ 3136185029Spjd VERIFY(nvlist_alloc(&zct.zct_zplprops, 3137185029Spjd NV_UNIQUE_NAME, KM_SLEEP) == 0); 3138185029Spjd error = zfs_fill_zplprops(zc->zc_name, nvprops, 3139185029Spjd zct.zct_zplprops, &is_insensitive); 3140185029Spjd if (error != 0) { 3141185029Spjd nvlist_free(nvprops); 3142185029Spjd nvlist_free(zct.zct_zplprops); 3143185029Spjd return (error); 3144185029Spjd } 3145168404Spjd } 3146219089Spjd error = dmu_objset_create(zc->zc_name, type, 3147185029Spjd is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct); 3148185029Spjd nvlist_free(zct.zct_zplprops); 3149168404Spjd } 3150168404Spjd 3151168404Spjd /* 3152168404Spjd * It would be nice to do this atomically. 3153168404Spjd */ 3154168404Spjd if (error == 0) { 3155219089Spjd error = zfs_set_prop_nvlist(zc->zc_name, ZPROP_SRC_LOCAL, 3156219089Spjd nvprops, NULL); 3157219089Spjd if (error != 0) 3158219089Spjd (void) dmu_objset_destroy(zc->zc_name, B_FALSE); 3159168404Spjd } 3160185029Spjd nvlist_free(nvprops); 3161219089Spjd#ifdef __FreeBSD__ 3162219089Spjd if (error == 0 && type == DMU_OST_ZVOL) 3163219089Spjd zvol_create_minors(zc->zc_name); 3164219089Spjd#endif 3165168404Spjd return (error); 3166168404Spjd} 3167168404Spjd 3168185029Spjd/* 3169185029Spjd * inputs: 3170185029Spjd * zc_name name of filesystem 3171185029Spjd * zc_value short name of snapshot 3172185029Spjd * zc_cookie recursive flag 3173209962Smm * zc_nvlist_src[_size] property list 3174185029Spjd * 3175219089Spjd * outputs: 3176219089Spjd * zc_value short snapname (i.e. part after the '@') 3177185029Spjd */ 3178185029Spjdstatic int 3179168404Spjdzfs_ioc_snapshot(zfs_cmd_t *zc) 3180168404Spjd{ 3181185029Spjd nvlist_t *nvprops = NULL; 3182185029Spjd int error; 3183185029Spjd boolean_t recursive = zc->zc_cookie; 3184185029Spjd 3185168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 3186168404Spjd return (EINVAL); 3187185029Spjd 3188185029Spjd if (zc->zc_nvlist_src != 0 && 3189185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3190219089Spjd zc->zc_iflags, &nvprops)) != 0) 3191185029Spjd return (error); 3192185029Spjd 3193209962Smm error = zfs_check_userprops(zc->zc_name, nvprops); 3194209962Smm if (error) 3195209962Smm goto out; 3196185029Spjd 3197219089Spjd if (!nvlist_empty(nvprops) && 3198209962Smm zfs_earlier_version(zc->zc_name, SPA_VERSION_SNAP_PROPS)) { 3199209962Smm error = ENOTSUP; 3200209962Smm goto out; 3201185029Spjd } 3202209962Smm 3203219089Spjd error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, NULL, 3204219089Spjd nvprops, recursive, B_FALSE, -1); 3205209962Smm 3206209962Smmout: 3207185029Spjd nvlist_free(nvprops); 3208185029Spjd return (error); 3209168404Spjd} 3210168404Spjd 3211168676Spjdint 3212219089Spjdzfs_unmount_snap(const char *name, void *arg) 3213168404Spjd{ 3214168404Spjd vfs_t *vfsp = NULL; 3215168404Spjd 3216185029Spjd if (arg) { 3217185029Spjd char *snapname = arg; 3218219089Spjd char *fullname = kmem_asprintf("%s@%s", name, snapname); 3219219089Spjd vfsp = zfs_get_vfs(fullname); 3220219089Spjd strfree(fullname); 3221168404Spjd } else if (strchr(name, '@')) { 3222168404Spjd vfsp = zfs_get_vfs(name); 3223168404Spjd } 3224168404Spjd 3225168404Spjd if (vfsp) { 3226168404Spjd /* 3227168404Spjd * Always force the unmount for snapshots. 3228168404Spjd */ 3229168404Spjd int flag = MS_FORCE; 3230168404Spjd int err; 3231168404Spjd 3232168404Spjd if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 3233168404Spjd VFS_RELE(vfsp); 3234168404Spjd return (err); 3235168404Spjd } 3236168404Spjd VFS_RELE(vfsp); 3237168404Spjd mtx_lock(&Giant); /* dounmount() */ 3238168404Spjd dounmount(vfsp, flag, curthread); 3239168404Spjd mtx_unlock(&Giant); /* dounmount() */ 3240168404Spjd } 3241168404Spjd return (0); 3242168404Spjd} 3243168404Spjd 3244185029Spjd/* 3245185029Spjd * inputs: 3246228103Smm * zc_name name of filesystem, snaps must be under it 3247228103Smm * zc_nvlist_src[_size] full names of snapshots to destroy 3248219089Spjd * zc_defer_destroy mark for deferred destroy 3249185029Spjd * 3250228103Smm * outputs: 3251228103Smm * zc_name on failure, name of failed snapshot 3252185029Spjd */ 3253168404Spjdstatic int 3254228103Smmzfs_ioc_destroy_snaps_nvl(zfs_cmd_t *zc) 3255168404Spjd{ 3256228103Smm int err, len; 3257228103Smm nvlist_t *nvl; 3258228103Smm nvpair_t *pair; 3259168404Spjd 3260228103Smm if ((err = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3261228103Smm zc->zc_iflags, &nvl)) != 0) { 3262228103Smm#ifndef __FreeBSD__ 3263168404Spjd return (err); 3264228103Smm#else 3265228103Smm /* 3266228103Smm * We are probably called by older binaries, 3267228103Smm * allocate and populate nvlist with recursive snapshots 3268228103Smm */ 3269228103Smm if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 3270228103Smm return (EINVAL); 3271228103Smm VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); 3272228103Smm err = dmu_get_recursive_snaps_nvl(zc->zc_name, 3273228103Smm zc->zc_value, nvl); 3274228103Smm if (err) { 3275228103Smm nvlist_free(nvl); 3276228103Smm return (err); 3277228103Smm } 3278228103Smm#endif /* __FreeBSD__ */ 3279228103Smm } 3280228103Smm 3281228103Smm len = strlen(zc->zc_name); 3282228103Smm for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL; 3283228103Smm pair = nvlist_next_nvpair(nvl, pair)) { 3284228103Smm const char *name = nvpair_name(pair); 3285228103Smm /* 3286228103Smm * The snap name must be underneath the zc_name. This ensures 3287228103Smm * that our permission checks were legitimate. 3288228103Smm */ 3289228103Smm if (strncmp(zc->zc_name, name, len) != 0 || 3290228103Smm (name[len] != '@' && name[len] != '/')) { 3291228103Smm nvlist_free(nvl); 3292228103Smm return (EINVAL); 3293228103Smm } 3294228103Smm 3295228103Smm (void) zfs_unmount_snap(name, NULL); 3296242862Savg (void) zvol_remove_minor(name); 3297228103Smm } 3298228103Smm 3299228103Smm err = dmu_snapshots_destroy_nvl(nvl, zc->zc_defer_destroy, 3300228103Smm zc->zc_name); 3301228103Smm nvlist_free(nvl); 3302228103Smm return (err); 3303168404Spjd} 3304168404Spjd 3305185029Spjd/* 3306185029Spjd * inputs: 3307185029Spjd * zc_name name of dataset to destroy 3308185029Spjd * zc_objset_type type of objset 3309219089Spjd * zc_defer_destroy mark for deferred destroy 3310185029Spjd * 3311185029Spjd * outputs: none 3312185029Spjd */ 3313168404Spjdstatic int 3314168404Spjdzfs_ioc_destroy(zfs_cmd_t *zc) 3315168404Spjd{ 3316219089Spjd int err; 3317168404Spjd if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 3318219089Spjd err = zfs_unmount_snap(zc->zc_name, NULL); 3319168404Spjd if (err) 3320168404Spjd return (err); 3321168404Spjd } 3322168404Spjd 3323219089Spjd err = dmu_objset_destroy(zc->zc_name, zc->zc_defer_destroy); 3324219089Spjd if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0) 3325219089Spjd (void) zvol_remove_minor(zc->zc_name); 3326219089Spjd return (err); 3327168404Spjd} 3328168404Spjd 3329185029Spjd/* 3330185029Spjd * inputs: 3331185029Spjd * zc_name name of dataset to rollback (to most recent snapshot) 3332185029Spjd * 3333185029Spjd * outputs: none 3334185029Spjd */ 3335168404Spjdstatic int 3336168404Spjdzfs_ioc_rollback(zfs_cmd_t *zc) 3337168404Spjd{ 3338219089Spjd dsl_dataset_t *ds, *clone; 3339185029Spjd int error; 3340219089Spjd zfsvfs_t *zfsvfs; 3341219089Spjd char *clone_name; 3342185029Spjd 3343219089Spjd error = dsl_dataset_hold(zc->zc_name, FTAG, &ds); 3344219089Spjd if (error) 3345219089Spjd return (error); 3346219089Spjd 3347219089Spjd /* must not be a snapshot */ 3348219089Spjd if (dsl_dataset_is_snapshot(ds)) { 3349219089Spjd dsl_dataset_rele(ds, FTAG); 3350219089Spjd return (EINVAL); 3351219089Spjd } 3352219089Spjd 3353219089Spjd /* must have a most recent snapshot */ 3354219089Spjd if (ds->ds_phys->ds_prev_snap_txg < TXG_INITIAL) { 3355219089Spjd dsl_dataset_rele(ds, FTAG); 3356219089Spjd return (EINVAL); 3357219089Spjd } 3358219089Spjd 3359185029Spjd /* 3360219089Spjd * Create clone of most recent snapshot. 3361185029Spjd */ 3362219089Spjd clone_name = kmem_asprintf("%s/%%rollback", zc->zc_name); 3363219089Spjd error = dmu_objset_clone(clone_name, ds->ds_prev, DS_FLAG_INCONSISTENT); 3364185029Spjd if (error) 3365219089Spjd goto out; 3366185029Spjd 3367219089Spjd error = dsl_dataset_own(clone_name, B_TRUE, FTAG, &clone); 3368219089Spjd if (error) 3369219089Spjd goto out; 3370219089Spjd 3371219089Spjd /* 3372219089Spjd * Do clone swap. 3373219089Spjd */ 3374209962Smm if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 3375219089Spjd error = zfs_suspend_fs(zfsvfs); 3376185029Spjd if (error == 0) { 3377185029Spjd int resume_err; 3378185029Spjd 3379219089Spjd if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 3380219089Spjd error = dsl_dataset_clone_swap(clone, ds, 3381219089Spjd B_TRUE); 3382219089Spjd dsl_dataset_disown(ds, FTAG); 3383219089Spjd ds = NULL; 3384219089Spjd } else { 3385219089Spjd error = EBUSY; 3386219089Spjd } 3387219089Spjd resume_err = zfs_resume_fs(zfsvfs, zc->zc_name); 3388185029Spjd error = error ? error : resume_err; 3389185029Spjd } 3390185029Spjd VFS_RELE(zfsvfs->z_vfs); 3391185029Spjd } else { 3392219089Spjd if (dsl_dataset_tryown(ds, B_FALSE, FTAG)) { 3393219089Spjd error = dsl_dataset_clone_swap(clone, ds, B_TRUE); 3394219089Spjd dsl_dataset_disown(ds, FTAG); 3395219089Spjd ds = NULL; 3396219089Spjd } else { 3397219089Spjd error = EBUSY; 3398219089Spjd } 3399185029Spjd } 3400185029Spjd 3401219089Spjd /* 3402219089Spjd * Destroy clone (which also closes it). 3403219089Spjd */ 3404219089Spjd (void) dsl_dataset_destroy(clone, FTAG, B_FALSE); 3405219089Spjd 3406219089Spjdout: 3407219089Spjd strfree(clone_name); 3408219089Spjd if (ds) 3409219089Spjd dsl_dataset_rele(ds, FTAG); 3410185029Spjd return (error); 3411168404Spjd} 3412168404Spjd 3413185029Spjd/* 3414185029Spjd * inputs: 3415185029Spjd * zc_name old name of dataset 3416185029Spjd * zc_value new name of dataset 3417185029Spjd * zc_cookie recursive flag (only valid for snapshots) 3418185029Spjd * 3419185029Spjd * outputs: none 3420185029Spjd */ 3421168404Spjdstatic int 3422168404Spjdzfs_ioc_rename(zfs_cmd_t *zc) 3423168404Spjd{ 3424226676Spjd int flags = 0; 3425168676Spjd 3426226676Spjd if (zc->zc_cookie & 1) 3427226676Spjd flags |= ZFS_RENAME_RECURSIVE; 3428226676Spjd if (zc->zc_cookie & 2) 3429226707Spjd flags |= ZFS_RENAME_ALLOW_MOUNTED; 3430226676Spjd 3431168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 3432185029Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 3433185029Spjd strchr(zc->zc_value, '%')) 3434168404Spjd return (EINVAL); 3435168404Spjd 3436168676Spjd /* 3437168676Spjd * Unmount snapshot unless we're doing a recursive rename, 3438168676Spjd * in which case the dataset code figures out which snapshots 3439168676Spjd * to unmount. 3440168676Spjd */ 3441226676Spjd if (!(flags & ZFS_RENAME_RECURSIVE) && 3442226676Spjd strchr(zc->zc_name, '@') != NULL && 3443168404Spjd zc->zc_objset_type == DMU_OST_ZFS) { 3444168404Spjd int err = zfs_unmount_snap(zc->zc_name, NULL); 3445168404Spjd if (err) 3446168404Spjd return (err); 3447168404Spjd } 3448226676Spjd return (dmu_objset_rename(zc->zc_name, zc->zc_value, flags)); 3449168404Spjd} 3450168404Spjd 3451219089Spjdstatic int 3452219089Spjdzfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) 3453185029Spjd{ 3454219089Spjd const char *propname = nvpair_name(pair); 3455219089Spjd boolean_t issnap = (strchr(dsname, '@') != NULL); 3456219089Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 3457219089Spjd uint64_t intval; 3458219089Spjd int err; 3459219089Spjd 3460219089Spjd if (prop == ZPROP_INVAL) { 3461219089Spjd if (zfs_prop_user(propname)) { 3462219089Spjd if (err = zfs_secpolicy_write_perms(dsname, 3463219089Spjd ZFS_DELEG_PERM_USERPROP, cr)) 3464219089Spjd return (err); 3465219089Spjd return (0); 3466219089Spjd } 3467219089Spjd 3468219089Spjd if (!issnap && zfs_prop_userquota(propname)) { 3469219089Spjd const char *perm = NULL; 3470219089Spjd const char *uq_prefix = 3471219089Spjd zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA]; 3472219089Spjd const char *gq_prefix = 3473219089Spjd zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA]; 3474219089Spjd 3475219089Spjd if (strncmp(propname, uq_prefix, 3476219089Spjd strlen(uq_prefix)) == 0) { 3477219089Spjd perm = ZFS_DELEG_PERM_USERQUOTA; 3478219089Spjd } else if (strncmp(propname, gq_prefix, 3479219089Spjd strlen(gq_prefix)) == 0) { 3480219089Spjd perm = ZFS_DELEG_PERM_GROUPQUOTA; 3481219089Spjd } else { 3482219089Spjd /* USERUSED and GROUPUSED are read-only */ 3483219089Spjd return (EINVAL); 3484219089Spjd } 3485219089Spjd 3486219089Spjd if (err = zfs_secpolicy_write_perms(dsname, perm, cr)) 3487219089Spjd return (err); 3488219089Spjd return (0); 3489219089Spjd } 3490219089Spjd 3491219089Spjd return (EINVAL); 3492219089Spjd } 3493219089Spjd 3494219089Spjd if (issnap) 3495219089Spjd return (EINVAL); 3496219089Spjd 3497219089Spjd if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 3498219089Spjd /* 3499219089Spjd * dsl_prop_get_all_impl() returns properties in this 3500219089Spjd * format. 3501219089Spjd */ 3502219089Spjd nvlist_t *attrs; 3503219089Spjd VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 3504219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 3505219089Spjd &pair) == 0); 3506219089Spjd } 3507219089Spjd 3508219089Spjd /* 3509219089Spjd * Check that this value is valid for this pool version 3510219089Spjd */ 3511219089Spjd switch (prop) { 3512219089Spjd case ZFS_PROP_COMPRESSION: 3513219089Spjd /* 3514219089Spjd * If the user specified gzip compression, make sure 3515219089Spjd * the SPA supports it. We ignore any errors here since 3516219089Spjd * we'll catch them later. 3517219089Spjd */ 3518219089Spjd if (nvpair_type(pair) == DATA_TYPE_UINT64 && 3519219089Spjd nvpair_value_uint64(pair, &intval) == 0) { 3520219089Spjd if (intval >= ZIO_COMPRESS_GZIP_1 && 3521219089Spjd intval <= ZIO_COMPRESS_GZIP_9 && 3522219089Spjd zfs_earlier_version(dsname, 3523219089Spjd SPA_VERSION_GZIP_COMPRESSION)) { 3524219089Spjd return (ENOTSUP); 3525219089Spjd } 3526219089Spjd 3527219089Spjd if (intval == ZIO_COMPRESS_ZLE && 3528219089Spjd zfs_earlier_version(dsname, 3529219089Spjd SPA_VERSION_ZLE_COMPRESSION)) 3530219089Spjd return (ENOTSUP); 3531219089Spjd 3532246586Sdelphij if (intval == ZIO_COMPRESS_LZ4) { 3533246586Sdelphij zfeature_info_t *feature = 3534246586Sdelphij &spa_feature_table[ 3535246586Sdelphij SPA_FEATURE_LZ4_COMPRESS]; 3536246586Sdelphij spa_t *spa; 3537246586Sdelphij 3538246586Sdelphij if ((err = spa_open(dsname, &spa, FTAG)) != 0) 3539246586Sdelphij return (err); 3540246586Sdelphij 3541246586Sdelphij if (!spa_feature_is_enabled(spa, feature)) { 3542246586Sdelphij spa_close(spa, FTAG); 3543246586Sdelphij return (ENOTSUP); 3544246586Sdelphij } 3545246586Sdelphij spa_close(spa, FTAG); 3546246586Sdelphij } 3547246586Sdelphij 3548219089Spjd /* 3549219089Spjd * If this is a bootable dataset then 3550219089Spjd * verify that the compression algorithm 3551219089Spjd * is supported for booting. We must return 3552219089Spjd * something other than ENOTSUP since it 3553219089Spjd * implies a downrev pool version. 3554219089Spjd */ 3555219089Spjd if (zfs_is_bootfs(dsname) && 3556219089Spjd !BOOTFS_COMPRESS_VALID(intval)) { 3557219089Spjd return (ERANGE); 3558219089Spjd } 3559219089Spjd } 3560219089Spjd break; 3561219089Spjd 3562219089Spjd case ZFS_PROP_COPIES: 3563219089Spjd if (zfs_earlier_version(dsname, SPA_VERSION_DITTO_BLOCKS)) 3564219089Spjd return (ENOTSUP); 3565219089Spjd break; 3566219089Spjd 3567219089Spjd case ZFS_PROP_DEDUP: 3568219089Spjd if (zfs_earlier_version(dsname, SPA_VERSION_DEDUP)) 3569219089Spjd return (ENOTSUP); 3570219089Spjd break; 3571219089Spjd 3572219089Spjd case ZFS_PROP_SHARESMB: 3573219089Spjd if (zpl_earlier_version(dsname, ZPL_VERSION_FUID)) 3574219089Spjd return (ENOTSUP); 3575219089Spjd break; 3576219089Spjd 3577219089Spjd case ZFS_PROP_ACLINHERIT: 3578219089Spjd if (nvpair_type(pair) == DATA_TYPE_UINT64 && 3579219089Spjd nvpair_value_uint64(pair, &intval) == 0) { 3580219089Spjd if (intval == ZFS_ACL_PASSTHROUGH_X && 3581219089Spjd zfs_earlier_version(dsname, 3582219089Spjd SPA_VERSION_PASSTHROUGH_X)) 3583219089Spjd return (ENOTSUP); 3584219089Spjd } 3585219089Spjd break; 3586219089Spjd } 3587219089Spjd 3588219089Spjd return (zfs_secpolicy_setprop(dsname, prop, pair, CRED())); 3589219089Spjd} 3590219089Spjd 3591219089Spjd/* 3592246586Sdelphij * Activates a feature on a pool in response to a property setting. This 3593246586Sdelphij * creates a new sync task which modifies the pool to reflect the feature 3594246586Sdelphij * as being active. 3595246586Sdelphij */ 3596246586Sdelphijstatic int 3597246586Sdelphijzfs_prop_activate_feature(dsl_pool_t *dp, zfeature_info_t *feature) 3598246586Sdelphij{ 3599246586Sdelphij int err; 3600246586Sdelphij 3601246586Sdelphij /* EBUSY here indicates that the feature is already active */ 3602246586Sdelphij err = dsl_sync_task_do(dp, zfs_prop_activate_feature_check, 3603246586Sdelphij zfs_prop_activate_feature_sync, dp->dp_spa, feature, 2); 3604246586Sdelphij 3605246586Sdelphij if (err != 0 && err != EBUSY) 3606246586Sdelphij return (err); 3607246586Sdelphij else 3608246586Sdelphij return (0); 3609246586Sdelphij} 3610246586Sdelphij 3611246586Sdelphij/* 3612246586Sdelphij * Checks for a race condition to make sure we don't increment a feature flag 3613246586Sdelphij * multiple times. 3614246586Sdelphij */ 3615246586Sdelphij/*ARGSUSED*/ 3616246586Sdelphijstatic int 3617246586Sdelphijzfs_prop_activate_feature_check(void *arg1, void *arg2, dmu_tx_t *tx) 3618246586Sdelphij{ 3619246586Sdelphij spa_t *spa = arg1; 3620246586Sdelphij zfeature_info_t *feature = arg2; 3621246586Sdelphij 3622246586Sdelphij if (!spa_feature_is_active(spa, feature)) 3623246586Sdelphij return (0); 3624246586Sdelphij else 3625246586Sdelphij return (EBUSY); 3626246586Sdelphij} 3627246586Sdelphij 3628246586Sdelphij/* 3629246586Sdelphij * The callback invoked on feature activation in the sync task caused by 3630246586Sdelphij * zfs_prop_activate_feature. 3631246586Sdelphij */ 3632246586Sdelphijstatic void 3633246586Sdelphijzfs_prop_activate_feature_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3634246586Sdelphij{ 3635246586Sdelphij spa_t *spa = arg1; 3636246586Sdelphij zfeature_info_t *feature = arg2; 3637246586Sdelphij 3638246586Sdelphij spa_feature_incr(spa, feature, tx); 3639246586Sdelphij} 3640246586Sdelphij 3641246586Sdelphij/* 3642219089Spjd * Removes properties from the given props list that fail permission checks 3643219089Spjd * needed to clear them and to restore them in case of a receive error. For each 3644219089Spjd * property, make sure we have both set and inherit permissions. 3645219089Spjd * 3646219089Spjd * Returns the first error encountered if any permission checks fail. If the 3647219089Spjd * caller provides a non-NULL errlist, it also gives the complete list of names 3648219089Spjd * of all the properties that failed a permission check along with the 3649219089Spjd * corresponding error numbers. The caller is responsible for freeing the 3650219089Spjd * returned errlist. 3651219089Spjd * 3652219089Spjd * If every property checks out successfully, zero is returned and the list 3653219089Spjd * pointed at by errlist is NULL. 3654219089Spjd */ 3655219089Spjdstatic int 3656219089Spjdzfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) 3657219089Spjd{ 3658185029Spjd zfs_cmd_t *zc; 3659219089Spjd nvpair_t *pair, *next_pair; 3660219089Spjd nvlist_t *errors; 3661219089Spjd int err, rv = 0; 3662185029Spjd 3663185029Spjd if (props == NULL) 3664219089Spjd return (0); 3665219089Spjd 3666219089Spjd VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 3667219089Spjd 3668185029Spjd zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 3669185029Spjd (void) strcpy(zc->zc_name, dataset); 3670219089Spjd pair = nvlist_next_nvpair(props, NULL); 3671219089Spjd while (pair != NULL) { 3672219089Spjd next_pair = nvlist_next_nvpair(props, pair); 3673219089Spjd 3674219089Spjd (void) strcpy(zc->zc_value, nvpair_name(pair)); 3675219089Spjd if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 || 3676219089Spjd (err = zfs_secpolicy_inherit(zc, CRED())) != 0) { 3677219089Spjd VERIFY(nvlist_remove_nvpair(props, pair) == 0); 3678219089Spjd VERIFY(nvlist_add_int32(errors, 3679219089Spjd zc->zc_value, err) == 0); 3680219089Spjd } 3681219089Spjd pair = next_pair; 3682185029Spjd } 3683185029Spjd kmem_free(zc, sizeof (zfs_cmd_t)); 3684219089Spjd 3685219089Spjd if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) { 3686219089Spjd nvlist_free(errors); 3687219089Spjd errors = NULL; 3688219089Spjd } else { 3689219089Spjd VERIFY(nvpair_value_int32(pair, &rv) == 0); 3690219089Spjd } 3691219089Spjd 3692219089Spjd if (errlist == NULL) 3693219089Spjd nvlist_free(errors); 3694219089Spjd else 3695219089Spjd *errlist = errors; 3696219089Spjd 3697219089Spjd return (rv); 3698185029Spjd} 3699185029Spjd 3700219089Spjdstatic boolean_t 3701219089Spjdpropval_equals(nvpair_t *p1, nvpair_t *p2) 3702219089Spjd{ 3703219089Spjd if (nvpair_type(p1) == DATA_TYPE_NVLIST) { 3704219089Spjd /* dsl_prop_get_all_impl() format */ 3705219089Spjd nvlist_t *attrs; 3706219089Spjd VERIFY(nvpair_value_nvlist(p1, &attrs) == 0); 3707219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 3708219089Spjd &p1) == 0); 3709219089Spjd } 3710219089Spjd 3711219089Spjd if (nvpair_type(p2) == DATA_TYPE_NVLIST) { 3712219089Spjd nvlist_t *attrs; 3713219089Spjd VERIFY(nvpair_value_nvlist(p2, &attrs) == 0); 3714219089Spjd VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 3715219089Spjd &p2) == 0); 3716219089Spjd } 3717219089Spjd 3718219089Spjd if (nvpair_type(p1) != nvpair_type(p2)) 3719219089Spjd return (B_FALSE); 3720219089Spjd 3721219089Spjd if (nvpair_type(p1) == DATA_TYPE_STRING) { 3722219089Spjd char *valstr1, *valstr2; 3723219089Spjd 3724219089Spjd VERIFY(nvpair_value_string(p1, (char **)&valstr1) == 0); 3725219089Spjd VERIFY(nvpair_value_string(p2, (char **)&valstr2) == 0); 3726219089Spjd return (strcmp(valstr1, valstr2) == 0); 3727219089Spjd } else { 3728219089Spjd uint64_t intval1, intval2; 3729219089Spjd 3730219089Spjd VERIFY(nvpair_value_uint64(p1, &intval1) == 0); 3731219089Spjd VERIFY(nvpair_value_uint64(p2, &intval2) == 0); 3732219089Spjd return (intval1 == intval2); 3733219089Spjd } 3734219089Spjd} 3735219089Spjd 3736185029Spjd/* 3737219089Spjd * Remove properties from props if they are not going to change (as determined 3738219089Spjd * by comparison with origprops). Remove them from origprops as well, since we 3739219089Spjd * do not need to clear or restore properties that won't change. 3740219089Spjd */ 3741219089Spjdstatic void 3742219089Spjdprops_reduce(nvlist_t *props, nvlist_t *origprops) 3743219089Spjd{ 3744219089Spjd nvpair_t *pair, *next_pair; 3745219089Spjd 3746219089Spjd if (origprops == NULL) 3747219089Spjd return; /* all props need to be received */ 3748219089Spjd 3749219089Spjd pair = nvlist_next_nvpair(props, NULL); 3750219089Spjd while (pair != NULL) { 3751219089Spjd const char *propname = nvpair_name(pair); 3752219089Spjd nvpair_t *match; 3753219089Spjd 3754219089Spjd next_pair = nvlist_next_nvpair(props, pair); 3755219089Spjd 3756219089Spjd if ((nvlist_lookup_nvpair(origprops, propname, 3757219089Spjd &match) != 0) || !propval_equals(pair, match)) 3758219089Spjd goto next; /* need to set received value */ 3759219089Spjd 3760219089Spjd /* don't clear the existing received value */ 3761219089Spjd (void) nvlist_remove_nvpair(origprops, match); 3762219089Spjd /* don't bother receiving the property */ 3763219089Spjd (void) nvlist_remove_nvpair(props, pair); 3764219089Spjdnext: 3765219089Spjd pair = next_pair; 3766219089Spjd } 3767219089Spjd} 3768219089Spjd 3769219089Spjd#ifdef DEBUG 3770219089Spjdstatic boolean_t zfs_ioc_recv_inject_err; 3771219089Spjd#endif 3772219089Spjd 3773219089Spjd/* 3774185029Spjd * inputs: 3775185029Spjd * zc_name name of containing filesystem 3776185029Spjd * zc_nvlist_src{_size} nvlist of properties to apply 3777185029Spjd * zc_value name of snapshot to create 3778185029Spjd * zc_string name of clone origin (if DRR_FLAG_CLONE) 3779185029Spjd * zc_cookie file descriptor to recv from 3780185029Spjd * zc_begin_record the BEGIN record of the stream (not byteswapped) 3781185029Spjd * zc_guid force flag 3782219089Spjd * zc_cleanup_fd cleanup-on-exit file descriptor 3783219089Spjd * zc_action_handle handle for this guid/ds mapping (or zero on first call) 3784185029Spjd * 3785185029Spjd * outputs: 3786185029Spjd * zc_cookie number of bytes read 3787219089Spjd * zc_nvlist_dst{_size} error for each unapplied received property 3788219089Spjd * zc_obj zprop_errflags_t 3789219089Spjd * zc_action_handle handle for this guid/ds mapping 3790185029Spjd */ 3791168404Spjdstatic int 3792185029Spjdzfs_ioc_recv(zfs_cmd_t *zc) 3793168404Spjd{ 3794185029Spjd file_t *fp; 3795185029Spjd objset_t *os; 3796185029Spjd dmu_recv_cookie_t drc; 3797185029Spjd boolean_t force = (boolean_t)zc->zc_guid; 3798219089Spjd int fd; 3799219089Spjd int error = 0; 3800219089Spjd int props_error = 0; 3801219089Spjd nvlist_t *errors; 3802185029Spjd offset_t off; 3803219089Spjd nvlist_t *props = NULL; /* sent properties */ 3804219089Spjd nvlist_t *origprops = NULL; /* existing properties */ 3805185029Spjd objset_t *origin = NULL; 3806185029Spjd char *tosnap; 3807185029Spjd char tofs[ZFS_MAXNAMELEN]; 3808219089Spjd boolean_t first_recvd_props = B_FALSE; 3809168404Spjd 3810168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 3811185029Spjd strchr(zc->zc_value, '@') == NULL || 3812185029Spjd strchr(zc->zc_value, '%')) 3813168404Spjd return (EINVAL); 3814168404Spjd 3815185029Spjd (void) strcpy(tofs, zc->zc_value); 3816185029Spjd tosnap = strchr(tofs, '@'); 3817219089Spjd *tosnap++ = '\0'; 3818185029Spjd 3819185029Spjd if (zc->zc_nvlist_src != 0 && 3820185029Spjd (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3821219089Spjd zc->zc_iflags, &props)) != 0) 3822168404Spjd return (error); 3823168404Spjd 3824185029Spjd fd = zc->zc_cookie; 3825247602Spjd fp = getf(fd, CAP_PREAD); 3826185029Spjd if (fp == NULL) { 3827185029Spjd nvlist_free(props); 3828185029Spjd return (EBADF); 3829185029Spjd } 3830168404Spjd 3831219089Spjd VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 3832219089Spjd 3833219089Spjd if (props && dmu_objset_hold(tofs, FTAG, &os) == 0) { 3834219089Spjd if ((spa_version(os->os_spa) >= SPA_VERSION_RECVD_PROPS) && 3835219089Spjd !dsl_prop_get_hasrecvd(os)) { 3836219089Spjd first_recvd_props = B_TRUE; 3837185029Spjd } 3838219089Spjd 3839185029Spjd /* 3840219089Spjd * If new received properties are supplied, they are to 3841219089Spjd * completely replace the existing received properties, so stash 3842219089Spjd * away the existing ones. 3843185029Spjd */ 3844219089Spjd if (dsl_prop_get_received(os, &origprops) == 0) { 3845219089Spjd nvlist_t *errlist = NULL; 3846219089Spjd /* 3847219089Spjd * Don't bother writing a property if its value won't 3848219089Spjd * change (and avoid the unnecessary security checks). 3849219089Spjd * 3850219089Spjd * The first receive after SPA_VERSION_RECVD_PROPS is a 3851219089Spjd * special case where we blow away all local properties 3852219089Spjd * regardless. 3853219089Spjd */ 3854219089Spjd if (!first_recvd_props) 3855219089Spjd props_reduce(props, origprops); 3856219089Spjd if (zfs_check_clearable(tofs, origprops, 3857219089Spjd &errlist) != 0) 3858219089Spjd (void) nvlist_merge(errors, errlist, 0); 3859219089Spjd nvlist_free(errlist); 3860219089Spjd } 3861185029Spjd 3862219089Spjd dmu_objset_rele(os, FTAG); 3863185029Spjd } 3864185029Spjd 3865185029Spjd if (zc->zc_string[0]) { 3866219089Spjd error = dmu_objset_hold(zc->zc_string, FTAG, &origin); 3867185029Spjd if (error) 3868185029Spjd goto out; 3869185029Spjd } 3870185029Spjd 3871219089Spjd error = dmu_recv_begin(tofs, tosnap, zc->zc_top_ds, 3872219089Spjd &zc->zc_begin_record, force, origin, &drc); 3873185029Spjd if (origin) 3874219089Spjd dmu_objset_rele(origin, FTAG); 3875185029Spjd if (error) 3876185029Spjd goto out; 3877185029Spjd 3878185029Spjd /* 3879219089Spjd * Set properties before we receive the stream so that they are applied 3880219089Spjd * to the new data. Note that we must call dmu_recv_stream() if 3881219089Spjd * dmu_recv_begin() succeeds. 3882185029Spjd */ 3883185029Spjd if (props) { 3884219089Spjd nvlist_t *errlist; 3885219089Spjd 3886219089Spjd if (dmu_objset_from_ds(drc.drc_logical_ds, &os) == 0) { 3887219089Spjd if (drc.drc_newfs) { 3888219089Spjd if (spa_version(os->os_spa) >= 3889219089Spjd SPA_VERSION_RECVD_PROPS) 3890219089Spjd first_recvd_props = B_TRUE; 3891219089Spjd } else if (origprops != NULL) { 3892219089Spjd if (clear_received_props(os, tofs, origprops, 3893219089Spjd first_recvd_props ? NULL : props) != 0) 3894219089Spjd zc->zc_obj |= ZPROP_ERR_NOCLEAR; 3895219089Spjd } else { 3896219089Spjd zc->zc_obj |= ZPROP_ERR_NOCLEAR; 3897219089Spjd } 3898219089Spjd dsl_prop_set_hasrecvd(os); 3899219089Spjd } else if (!drc.drc_newfs) { 3900219089Spjd zc->zc_obj |= ZPROP_ERR_NOCLEAR; 3901219089Spjd } 3902219089Spjd 3903219089Spjd (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, 3904219089Spjd props, &errlist); 3905219089Spjd (void) nvlist_merge(errors, errlist, 0); 3906219089Spjd nvlist_free(errlist); 3907219089Spjd } 3908219089Spjd 3909219089Spjd if (fit_error_list(zc, &errors) != 0 || put_nvlist(zc, errors) != 0) { 3910185029Spjd /* 3911219089Spjd * Caller made zc->zc_nvlist_dst less than the minimum expected 3912219089Spjd * size or supplied an invalid address. 3913185029Spjd */ 3914219089Spjd props_error = EINVAL; 3915185029Spjd } 3916185029Spjd 3917185029Spjd off = fp->f_offset; 3918219089Spjd error = dmu_recv_stream(&drc, fp, &off, zc->zc_cleanup_fd, 3919219089Spjd &zc->zc_action_handle); 3920185029Spjd 3921219089Spjd if (error == 0) { 3922219089Spjd zfsvfs_t *zfsvfs = NULL; 3923185029Spjd 3924219089Spjd if (getzfsvfs(tofs, &zfsvfs) == 0) { 3925219089Spjd /* online recv */ 3926219089Spjd int end_err; 3927185029Spjd 3928219089Spjd error = zfs_suspend_fs(zfsvfs); 3929219089Spjd /* 3930219089Spjd * If the suspend fails, then the recv_end will 3931219089Spjd * likely also fail, and clean up after itself. 3932219089Spjd */ 3933219089Spjd end_err = dmu_recv_end(&drc); 3934219089Spjd if (error == 0) 3935219089Spjd error = zfs_resume_fs(zfsvfs, tofs); 3936219089Spjd error = error ? error : end_err; 3937219089Spjd VFS_RELE(zfsvfs->z_vfs); 3938219089Spjd } else { 3939185029Spjd error = dmu_recv_end(&drc); 3940185029Spjd } 3941185029Spjd } 3942185029Spjd 3943185029Spjd zc->zc_cookie = off - fp->f_offset; 3944185029Spjd if (off >= 0 && off <= MAXOFFSET_T) 3945185029Spjd fp->f_offset = off; 3946185029Spjd 3947219089Spjd#ifdef DEBUG 3948219089Spjd if (zfs_ioc_recv_inject_err) { 3949219089Spjd zfs_ioc_recv_inject_err = B_FALSE; 3950219089Spjd error = 1; 3951219089Spjd } 3952219089Spjd#endif 3953243497Savg 3954243497Savg#ifdef __FreeBSD__ 3955243497Savg if (error == 0) 3956243497Savg zvol_create_minors(tofs); 3957243497Savg#endif 3958243497Savg 3959185029Spjd /* 3960185029Spjd * On error, restore the original props. 3961185029Spjd */ 3962185029Spjd if (error && props) { 3963219089Spjd if (dmu_objset_hold(tofs, FTAG, &os) == 0) { 3964219089Spjd if (clear_received_props(os, tofs, props, NULL) != 0) { 3965219089Spjd /* 3966219089Spjd * We failed to clear the received properties. 3967219089Spjd * Since we may have left a $recvd value on the 3968219089Spjd * system, we can't clear the $hasrecvd flag. 3969219089Spjd */ 3970219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3971219089Spjd } else if (first_recvd_props) { 3972219089Spjd dsl_prop_unset_hasrecvd(os); 3973219089Spjd } 3974219089Spjd dmu_objset_rele(os, FTAG); 3975219089Spjd } else if (!drc.drc_newfs) { 3976219089Spjd /* We failed to clear the received properties. */ 3977219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3978219089Spjd } 3979219089Spjd 3980219089Spjd if (origprops == NULL && !drc.drc_newfs) { 3981219089Spjd /* We failed to stash the original properties. */ 3982219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 3983219089Spjd } 3984219089Spjd 3985219089Spjd /* 3986219089Spjd * dsl_props_set() will not convert RECEIVED to LOCAL on or 3987219089Spjd * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL 3988219089Spjd * explictly if we're restoring local properties cleared in the 3989219089Spjd * first new-style receive. 3990219089Spjd */ 3991219089Spjd if (origprops != NULL && 3992219089Spjd zfs_set_prop_nvlist(tofs, (first_recvd_props ? 3993219089Spjd ZPROP_SRC_LOCAL : ZPROP_SRC_RECEIVED), 3994219089Spjd origprops, NULL) != 0) { 3995219089Spjd /* 3996219089Spjd * We stashed the original properties but failed to 3997219089Spjd * restore them. 3998219089Spjd */ 3999219089Spjd zc->zc_obj |= ZPROP_ERR_NORESTORE; 4000219089Spjd } 4001185029Spjd } 4002185029Spjdout: 4003185029Spjd nvlist_free(props); 4004185029Spjd nvlist_free(origprops); 4005219089Spjd nvlist_free(errors); 4006219089Spjd releasef(fd); 4007219089Spjd 4008219089Spjd if (error == 0) 4009219089Spjd error = props_error; 4010219089Spjd 4011168404Spjd return (error); 4012168404Spjd} 4013168404Spjd 4014185029Spjd/* 4015185029Spjd * inputs: 4016185029Spjd * zc_name name of snapshot to send 4017185029Spjd * zc_cookie file descriptor to send stream to 4018219089Spjd * zc_obj fromorigin flag (mutually exclusive with zc_fromobj) 4019219089Spjd * zc_sendobj objsetid of snapshot to send 4020219089Spjd * zc_fromobj objsetid of incremental fromsnap (may be zero) 4021228103Smm * zc_guid if set, estimate size of stream only. zc_cookie is ignored. 4022228103Smm * output size in zc_objset_type. 4023185029Spjd * 4024185029Spjd * outputs: none 4025185029Spjd */ 4026168404Spjdstatic int 4027185029Spjdzfs_ioc_send(zfs_cmd_t *zc) 4028168404Spjd{ 4029168404Spjd objset_t *fromsnap = NULL; 4030168404Spjd objset_t *tosnap; 4031185029Spjd int error; 4032185029Spjd offset_t off; 4033219089Spjd dsl_dataset_t *ds; 4034219089Spjd dsl_dataset_t *dsfrom = NULL; 4035219089Spjd spa_t *spa; 4036219089Spjd dsl_pool_t *dp; 4037228103Smm boolean_t estimate = (zc->zc_guid != 0); 4038168404Spjd 4039219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 4040168404Spjd if (error) 4041168404Spjd return (error); 4042168404Spjd 4043219089Spjd dp = spa_get_dsl(spa); 4044219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 4045219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 4046219089Spjd rw_exit(&dp->dp_config_rwlock); 4047219089Spjd if (error) { 4048219089Spjd spa_close(spa, FTAG); 4049219089Spjd return (error); 4050219089Spjd } 4051168404Spjd 4052219089Spjd error = dmu_objset_from_ds(ds, &tosnap); 4053219089Spjd if (error) { 4054219089Spjd dsl_dataset_rele(ds, FTAG); 4055219089Spjd spa_close(spa, FTAG); 4056219089Spjd return (error); 4057219089Spjd } 4058219089Spjd 4059219089Spjd if (zc->zc_fromobj != 0) { 4060219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 4061219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_fromobj, FTAG, &dsfrom); 4062219089Spjd rw_exit(&dp->dp_config_rwlock); 4063219089Spjd spa_close(spa, FTAG); 4064168404Spjd if (error) { 4065219089Spjd dsl_dataset_rele(ds, FTAG); 4066168404Spjd return (error); 4067168404Spjd } 4068219089Spjd error = dmu_objset_from_ds(dsfrom, &fromsnap); 4069219089Spjd if (error) { 4070219089Spjd dsl_dataset_rele(dsfrom, FTAG); 4071219089Spjd dsl_dataset_rele(ds, FTAG); 4072219089Spjd return (error); 4073219089Spjd } 4074219089Spjd } else { 4075219089Spjd spa_close(spa, FTAG); 4076168404Spjd } 4077168404Spjd 4078228103Smm if (estimate) { 4079228103Smm error = dmu_send_estimate(tosnap, fromsnap, zc->zc_obj, 4080228103Smm &zc->zc_objset_type); 4081228103Smm } else { 4082247602Spjd file_t *fp = getf(zc->zc_cookie, CAP_WRITE); 4083228103Smm if (fp == NULL) { 4084228103Smm dsl_dataset_rele(ds, FTAG); 4085228103Smm if (dsfrom) 4086228103Smm dsl_dataset_rele(dsfrom, FTAG); 4087228103Smm return (EBADF); 4088228103Smm } 4089168404Spjd 4090228103Smm off = fp->f_offset; 4091235222Smm error = dmu_send(tosnap, fromsnap, zc->zc_obj, 4092235222Smm zc->zc_cookie, fp, &off); 4093168404Spjd 4094228103Smm if (off >= 0 && off <= MAXOFFSET_T) 4095228103Smm fp->f_offset = off; 4096228103Smm releasef(zc->zc_cookie); 4097228103Smm } 4098219089Spjd if (dsfrom) 4099219089Spjd dsl_dataset_rele(dsfrom, FTAG); 4100219089Spjd dsl_dataset_rele(ds, FTAG); 4101168404Spjd return (error); 4102168404Spjd} 4103168404Spjd 4104235222Smm/* 4105235222Smm * inputs: 4106235222Smm * zc_name name of snapshot on which to report progress 4107235222Smm * zc_cookie file descriptor of send stream 4108235222Smm * 4109235222Smm * outputs: 4110235222Smm * zc_cookie number of bytes written in send stream thus far 4111235222Smm */ 4112168404Spjdstatic int 4113235222Smmzfs_ioc_send_progress(zfs_cmd_t *zc) 4114235222Smm{ 4115235222Smm dsl_dataset_t *ds; 4116235222Smm dmu_sendarg_t *dsp = NULL; 4117235222Smm int error; 4118235222Smm 4119235222Smm if ((error = dsl_dataset_hold(zc->zc_name, FTAG, &ds)) != 0) 4120235222Smm return (error); 4121235222Smm 4122235222Smm mutex_enter(&ds->ds_sendstream_lock); 4123235222Smm 4124235222Smm /* 4125235222Smm * Iterate over all the send streams currently active on this dataset. 4126235222Smm * If there's one which matches the specified file descriptor _and_ the 4127235222Smm * stream was started by the current process, return the progress of 4128235222Smm * that stream. 4129235222Smm */ 4130235222Smm for (dsp = list_head(&ds->ds_sendstreams); dsp != NULL; 4131235222Smm dsp = list_next(&ds->ds_sendstreams, dsp)) { 4132235222Smm if (dsp->dsa_outfd == zc->zc_cookie && 4133235222Smm dsp->dsa_proc == curproc) 4134235222Smm break; 4135235222Smm } 4136235222Smm 4137235222Smm if (dsp != NULL) 4138235222Smm zc->zc_cookie = *(dsp->dsa_off); 4139235222Smm else 4140235222Smm error = ENOENT; 4141235222Smm 4142235222Smm mutex_exit(&ds->ds_sendstream_lock); 4143235222Smm dsl_dataset_rele(ds, FTAG); 4144235222Smm return (error); 4145235222Smm} 4146235222Smm 4147235222Smmstatic int 4148168404Spjdzfs_ioc_inject_fault(zfs_cmd_t *zc) 4149168404Spjd{ 4150168404Spjd int id, error; 4151168404Spjd 4152168404Spjd error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 4153168404Spjd &zc->zc_inject_record); 4154168404Spjd 4155168404Spjd if (error == 0) 4156168404Spjd zc->zc_guid = (uint64_t)id; 4157168404Spjd 4158168404Spjd return (error); 4159168404Spjd} 4160168404Spjd 4161168404Spjdstatic int 4162168404Spjdzfs_ioc_clear_fault(zfs_cmd_t *zc) 4163168404Spjd{ 4164168404Spjd return (zio_clear_fault((int)zc->zc_guid)); 4165168404Spjd} 4166168404Spjd 4167168404Spjdstatic int 4168168404Spjdzfs_ioc_inject_list_next(zfs_cmd_t *zc) 4169168404Spjd{ 4170168404Spjd int id = (int)zc->zc_guid; 4171168404Spjd int error; 4172168404Spjd 4173168404Spjd error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 4174168404Spjd &zc->zc_inject_record); 4175168404Spjd 4176168404Spjd zc->zc_guid = id; 4177168404Spjd 4178168404Spjd return (error); 4179168404Spjd} 4180168404Spjd 4181168404Spjdstatic int 4182168404Spjdzfs_ioc_error_log(zfs_cmd_t *zc) 4183168404Spjd{ 4184168404Spjd spa_t *spa; 4185168404Spjd int error; 4186168404Spjd size_t count = (size_t)zc->zc_nvlist_dst_size; 4187168404Spjd 4188168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 4189168404Spjd return (error); 4190168404Spjd 4191168404Spjd error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 4192168404Spjd &count); 4193168404Spjd if (error == 0) 4194168404Spjd zc->zc_nvlist_dst_size = count; 4195168404Spjd else 4196168404Spjd zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 4197168404Spjd 4198168404Spjd spa_close(spa, FTAG); 4199168404Spjd 4200168404Spjd return (error); 4201168404Spjd} 4202168404Spjd 4203168404Spjdstatic int 4204168404Spjdzfs_ioc_clear(zfs_cmd_t *zc) 4205168404Spjd{ 4206168404Spjd spa_t *spa; 4207168404Spjd vdev_t *vd; 4208168404Spjd int error; 4209168404Spjd 4210185029Spjd /* 4211185029Spjd * On zpool clear we also fix up missing slogs 4212185029Spjd */ 4213185029Spjd mutex_enter(&spa_namespace_lock); 4214185029Spjd spa = spa_lookup(zc->zc_name); 4215185029Spjd if (spa == NULL) { 4216185029Spjd mutex_exit(&spa_namespace_lock); 4217185029Spjd return (EIO); 4218185029Spjd } 4219219089Spjd if (spa_get_log_state(spa) == SPA_LOG_MISSING) { 4220185029Spjd /* we need to let spa_open/spa_load clear the chains */ 4221219089Spjd spa_set_log_state(spa, SPA_LOG_CLEAR); 4222185029Spjd } 4223219089Spjd spa->spa_last_open_failed = 0; 4224185029Spjd mutex_exit(&spa_namespace_lock); 4225185029Spjd 4226219089Spjd if (zc->zc_cookie & ZPOOL_NO_REWIND) { 4227219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 4228219089Spjd } else { 4229219089Spjd nvlist_t *policy; 4230219089Spjd nvlist_t *config = NULL; 4231219089Spjd 4232219089Spjd if (zc->zc_nvlist_src == 0) 4233219089Spjd return (EINVAL); 4234219089Spjd 4235219089Spjd if ((error = get_nvlist(zc->zc_nvlist_src, 4236219089Spjd zc->zc_nvlist_src_size, zc->zc_iflags, &policy)) == 0) { 4237219089Spjd error = spa_open_rewind(zc->zc_name, &spa, FTAG, 4238219089Spjd policy, &config); 4239219089Spjd if (config != NULL) { 4240219089Spjd int err; 4241219089Spjd 4242219089Spjd if ((err = put_nvlist(zc, config)) != 0) 4243219089Spjd error = err; 4244219089Spjd nvlist_free(config); 4245219089Spjd } 4246219089Spjd nvlist_free(policy); 4247219089Spjd } 4248219089Spjd } 4249219089Spjd 4250219089Spjd if (error) 4251168404Spjd return (error); 4252168404Spjd 4253219089Spjd spa_vdev_state_enter(spa, SCL_NONE); 4254168404Spjd 4255168404Spjd if (zc->zc_guid == 0) { 4256168404Spjd vd = NULL; 4257185029Spjd } else { 4258185029Spjd vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 4259185029Spjd if (vd == NULL) { 4260185029Spjd (void) spa_vdev_state_exit(spa, NULL, ENODEV); 4261185029Spjd spa_close(spa, FTAG); 4262185029Spjd return (ENODEV); 4263185029Spjd } 4264168404Spjd } 4265168404Spjd 4266168404Spjd vdev_clear(spa, vd); 4267168404Spjd 4268185029Spjd (void) spa_vdev_state_exit(spa, NULL, 0); 4269168404Spjd 4270185029Spjd /* 4271185029Spjd * Resume any suspended I/Os. 4272185029Spjd */ 4273209962Smm if (zio_resume(spa) != 0) 4274209962Smm error = EIO; 4275185029Spjd 4276168404Spjd spa_close(spa, FTAG); 4277168404Spjd 4278209962Smm return (error); 4279168404Spjd} 4280168404Spjd 4281236155Smmstatic int 4282236155Smmzfs_ioc_pool_reopen(zfs_cmd_t *zc) 4283236155Smm{ 4284236155Smm spa_t *spa; 4285236155Smm int error; 4286236155Smm 4287236155Smm error = spa_open(zc->zc_name, &spa, FTAG); 4288236155Smm if (error) 4289236155Smm return (error); 4290236155Smm 4291236155Smm spa_vdev_state_enter(spa, SCL_NONE); 4292240133Smm 4293240133Smm /* 4294240133Smm * If a resilver is already in progress then set the 4295240133Smm * spa_scrub_reopen flag to B_TRUE so that we don't restart 4296240133Smm * the scan as a side effect of the reopen. Otherwise, let 4297240133Smm * vdev_open() decided if a resilver is required. 4298240133Smm */ 4299240133Smm spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool); 4300236155Smm vdev_reopen(spa->spa_root_vdev); 4301240133Smm spa->spa_scrub_reopen = B_FALSE; 4302240133Smm 4303236155Smm (void) spa_vdev_state_exit(spa, NULL, 0); 4304236155Smm spa_close(spa, FTAG); 4305236155Smm return (0); 4306236155Smm} 4307185029Spjd/* 4308185029Spjd * inputs: 4309185029Spjd * zc_name name of filesystem 4310185029Spjd * zc_value name of origin snapshot 4311185029Spjd * 4312219089Spjd * outputs: 4313219089Spjd * zc_string name of conflicting snapshot, if there is one 4314185029Spjd */ 4315168404Spjdstatic int 4316168404Spjdzfs_ioc_promote(zfs_cmd_t *zc) 4317168404Spjd{ 4318168404Spjd char *cp; 4319168404Spjd 4320168404Spjd /* 4321168404Spjd * We don't need to unmount *all* the origin fs's snapshots, but 4322168404Spjd * it's easier. 4323168404Spjd */ 4324168404Spjd cp = strchr(zc->zc_value, '@'); 4325168404Spjd if (cp) 4326168404Spjd *cp = '\0'; 4327168404Spjd (void) dmu_objset_find(zc->zc_value, 4328168404Spjd zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 4329219089Spjd return (dsl_dataset_promote(zc->zc_name, zc->zc_string)); 4330168404Spjd} 4331168404Spjd 4332185029Spjd/* 4333209962Smm * Retrieve a single {user|group}{used|quota}@... property. 4334209962Smm * 4335209962Smm * inputs: 4336209962Smm * zc_name name of filesystem 4337209962Smm * zc_objset_type zfs_userquota_prop_t 4338209962Smm * zc_value domain name (eg. "S-1-234-567-89") 4339209962Smm * zc_guid RID/UID/GID 4340209962Smm * 4341209962Smm * outputs: 4342209962Smm * zc_cookie property value 4343209962Smm */ 4344209962Smmstatic int 4345209962Smmzfs_ioc_userspace_one(zfs_cmd_t *zc) 4346209962Smm{ 4347209962Smm zfsvfs_t *zfsvfs; 4348209962Smm int error; 4349209962Smm 4350209962Smm if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 4351209962Smm return (EINVAL); 4352209962Smm 4353219089Spjd error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 4354209962Smm if (error) 4355209962Smm return (error); 4356209962Smm 4357209962Smm error = zfs_userspace_one(zfsvfs, 4358209962Smm zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 4359209962Smm zfsvfs_rele(zfsvfs, FTAG); 4360209962Smm 4361209962Smm return (error); 4362209962Smm} 4363209962Smm 4364209962Smm/* 4365209962Smm * inputs: 4366209962Smm * zc_name name of filesystem 4367209962Smm * zc_cookie zap cursor 4368209962Smm * zc_objset_type zfs_userquota_prop_t 4369209962Smm * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 4370209962Smm * 4371209962Smm * outputs: 4372209962Smm * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 4373209962Smm * zc_cookie zap cursor 4374209962Smm */ 4375209962Smmstatic int 4376209962Smmzfs_ioc_userspace_many(zfs_cmd_t *zc) 4377209962Smm{ 4378209962Smm zfsvfs_t *zfsvfs; 4379219089Spjd int bufsize = zc->zc_nvlist_dst_size; 4380209962Smm 4381219089Spjd if (bufsize <= 0) 4382219089Spjd return (ENOMEM); 4383219089Spjd 4384219089Spjd int error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 4385209962Smm if (error) 4386209962Smm return (error); 4387209962Smm 4388209962Smm void *buf = kmem_alloc(bufsize, KM_SLEEP); 4389209962Smm 4390209962Smm error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 4391209962Smm buf, &zc->zc_nvlist_dst_size); 4392209962Smm 4393209962Smm if (error == 0) { 4394221409Smarius error = ddi_copyout(buf, 4395209962Smm (void *)(uintptr_t)zc->zc_nvlist_dst, 4396221409Smarius zc->zc_nvlist_dst_size, zc->zc_iflags); 4397209962Smm } 4398209962Smm kmem_free(buf, bufsize); 4399209962Smm zfsvfs_rele(zfsvfs, FTAG); 4400209962Smm 4401209962Smm return (error); 4402209962Smm} 4403209962Smm 4404209962Smm/* 4405209962Smm * inputs: 4406209962Smm * zc_name name of filesystem 4407209962Smm * 4408209962Smm * outputs: 4409209962Smm * none 4410209962Smm */ 4411209962Smmstatic int 4412209962Smmzfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 4413209962Smm{ 4414209962Smm objset_t *os; 4415219089Spjd int error = 0; 4416209962Smm zfsvfs_t *zfsvfs; 4417209962Smm 4418209962Smm if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 4419219089Spjd if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { 4420209962Smm /* 4421209962Smm * If userused is not enabled, it may be because the 4422209962Smm * objset needs to be closed & reopened (to grow the 4423209962Smm * objset_phys_t). Suspend/resume the fs will do that. 4424209962Smm */ 4425219089Spjd error = zfs_suspend_fs(zfsvfs); 4426219089Spjd if (error == 0) 4427219089Spjd error = zfs_resume_fs(zfsvfs, zc->zc_name); 4428209962Smm } 4429209962Smm if (error == 0) 4430209962Smm error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 4431209962Smm VFS_RELE(zfsvfs->z_vfs); 4432209962Smm } else { 4433219089Spjd /* XXX kind of reading contents without owning */ 4434219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &os); 4435209962Smm if (error) 4436209962Smm return (error); 4437209962Smm 4438209962Smm error = dmu_objset_userspace_upgrade(os); 4439219089Spjd dmu_objset_rele(os, FTAG); 4440209962Smm } 4441209962Smm 4442209962Smm return (error); 4443209962Smm} 4444209962Smm 4445209962Smm#ifdef sun 4446209962Smm/* 4447185029Spjd * We don't want to have a hard dependency 4448185029Spjd * against some special symbols in sharefs 4449185029Spjd * nfs, and smbsrv. Determine them if needed when 4450185029Spjd * the first file system is shared. 4451185029Spjd * Neither sharefs, nfs or smbsrv are unloadable modules. 4452185029Spjd */ 4453185029Spjdint (*znfsexport_fs)(void *arg); 4454185029Spjdint (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 4455185029Spjdint (*zsmbexport_fs)(void *arg, boolean_t add_share); 4456185029Spjd 4457185029Spjdint zfs_nfsshare_inited; 4458185029Spjdint zfs_smbshare_inited; 4459185029Spjd 4460185029Spjdddi_modhandle_t nfs_mod; 4461185029Spjdddi_modhandle_t sharefs_mod; 4462185029Spjdddi_modhandle_t smbsrv_mod; 4463209962Smm#endif /* sun */ 4464185029Spjdkmutex_t zfs_share_lock; 4465185029Spjd 4466209962Smm#ifdef sun 4467168404Spjdstatic int 4468185029Spjdzfs_init_sharefs() 4469185029Spjd{ 4470185029Spjd int error; 4471185029Spjd 4472185029Spjd ASSERT(MUTEX_HELD(&zfs_share_lock)); 4473185029Spjd /* Both NFS and SMB shares also require sharetab support. */ 4474185029Spjd if (sharefs_mod == NULL && ((sharefs_mod = 4475185029Spjd ddi_modopen("fs/sharefs", 4476185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 4477185029Spjd return (ENOSYS); 4478185029Spjd } 4479185029Spjd if (zshare_fs == NULL && ((zshare_fs = 4480185029Spjd (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 4481185029Spjd ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 4482185029Spjd return (ENOSYS); 4483185029Spjd } 4484185029Spjd return (0); 4485185029Spjd} 4486219089Spjd#endif /* sun */ 4487185029Spjd 4488185029Spjdstatic int 4489185029Spjdzfs_ioc_share(zfs_cmd_t *zc) 4490185029Spjd{ 4491209962Smm#ifdef sun 4492185029Spjd int error; 4493185029Spjd int opcode; 4494185029Spjd 4495185029Spjd switch (zc->zc_share.z_sharetype) { 4496185029Spjd case ZFS_SHARE_NFS: 4497185029Spjd case ZFS_UNSHARE_NFS: 4498185029Spjd if (zfs_nfsshare_inited == 0) { 4499185029Spjd mutex_enter(&zfs_share_lock); 4500185029Spjd if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 4501185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 4502185029Spjd mutex_exit(&zfs_share_lock); 4503185029Spjd return (ENOSYS); 4504185029Spjd } 4505185029Spjd if (znfsexport_fs == NULL && 4506185029Spjd ((znfsexport_fs = (int (*)(void *)) 4507185029Spjd ddi_modsym(nfs_mod, 4508185029Spjd "nfs_export", &error)) == NULL)) { 4509185029Spjd mutex_exit(&zfs_share_lock); 4510185029Spjd return (ENOSYS); 4511185029Spjd } 4512185029Spjd error = zfs_init_sharefs(); 4513185029Spjd if (error) { 4514185029Spjd mutex_exit(&zfs_share_lock); 4515185029Spjd return (ENOSYS); 4516185029Spjd } 4517185029Spjd zfs_nfsshare_inited = 1; 4518185029Spjd mutex_exit(&zfs_share_lock); 4519185029Spjd } 4520185029Spjd break; 4521185029Spjd case ZFS_SHARE_SMB: 4522185029Spjd case ZFS_UNSHARE_SMB: 4523185029Spjd if (zfs_smbshare_inited == 0) { 4524185029Spjd mutex_enter(&zfs_share_lock); 4525185029Spjd if (smbsrv_mod == NULL && ((smbsrv_mod = 4526185029Spjd ddi_modopen("drv/smbsrv", 4527185029Spjd KRTLD_MODE_FIRST, &error)) == NULL)) { 4528185029Spjd mutex_exit(&zfs_share_lock); 4529185029Spjd return (ENOSYS); 4530185029Spjd } 4531185029Spjd if (zsmbexport_fs == NULL && ((zsmbexport_fs = 4532185029Spjd (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 4533185029Spjd "smb_server_share", &error)) == NULL)) { 4534185029Spjd mutex_exit(&zfs_share_lock); 4535185029Spjd return (ENOSYS); 4536185029Spjd } 4537185029Spjd error = zfs_init_sharefs(); 4538185029Spjd if (error) { 4539185029Spjd mutex_exit(&zfs_share_lock); 4540185029Spjd return (ENOSYS); 4541185029Spjd } 4542185029Spjd zfs_smbshare_inited = 1; 4543185029Spjd mutex_exit(&zfs_share_lock); 4544185029Spjd } 4545185029Spjd break; 4546185029Spjd default: 4547185029Spjd return (EINVAL); 4548185029Spjd } 4549185029Spjd 4550185029Spjd switch (zc->zc_share.z_sharetype) { 4551185029Spjd case ZFS_SHARE_NFS: 4552185029Spjd case ZFS_UNSHARE_NFS: 4553185029Spjd if (error = 4554185029Spjd znfsexport_fs((void *) 4555185029Spjd (uintptr_t)zc->zc_share.z_exportdata)) 4556185029Spjd return (error); 4557185029Spjd break; 4558185029Spjd case ZFS_SHARE_SMB: 4559185029Spjd case ZFS_UNSHARE_SMB: 4560185029Spjd if (error = zsmbexport_fs((void *) 4561185029Spjd (uintptr_t)zc->zc_share.z_exportdata, 4562185029Spjd zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 4563209962Smm B_TRUE: B_FALSE)) { 4564185029Spjd return (error); 4565185029Spjd } 4566185029Spjd break; 4567185029Spjd } 4568185029Spjd 4569185029Spjd opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 4570185029Spjd zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 4571185029Spjd SHAREFS_ADD : SHAREFS_REMOVE; 4572185029Spjd 4573185029Spjd /* 4574185029Spjd * Add or remove share from sharetab 4575185029Spjd */ 4576185029Spjd error = zshare_fs(opcode, 4577185029Spjd (void *)(uintptr_t)zc->zc_share.z_sharedata, 4578185029Spjd zc->zc_share.z_sharemax); 4579185029Spjd 4580185029Spjd return (error); 4581219089Spjd 4582219089Spjd#else /* !sun */ 4583185029Spjd return (ENOSYS); 4584219089Spjd#endif /* !sun */ 4585185029Spjd} 4586185029Spjd 4587209962Smmace_t full_access[] = { 4588209962Smm {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 4589209962Smm}; 4590209962Smm 4591219089Spjd/* 4592219089Spjd * inputs: 4593219089Spjd * zc_name name of containing filesystem 4594219089Spjd * zc_obj object # beyond which we want next in-use object # 4595219089Spjd * 4596219089Spjd * outputs: 4597219089Spjd * zc_obj next in-use object # 4598219089Spjd */ 4599219089Spjdstatic int 4600219089Spjdzfs_ioc_next_obj(zfs_cmd_t *zc) 4601219089Spjd{ 4602219089Spjd objset_t *os = NULL; 4603219089Spjd int error; 4604219089Spjd 4605219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &os); 4606219089Spjd if (error) 4607219089Spjd return (error); 4608219089Spjd 4609219089Spjd error = dmu_object_next(os, &zc->zc_obj, B_FALSE, 4610219089Spjd os->os_dsl_dataset->ds_phys->ds_prev_snap_txg); 4611219089Spjd 4612219089Spjd dmu_objset_rele(os, FTAG); 4613219089Spjd return (error); 4614219089Spjd} 4615219089Spjd 4616219089Spjd/* 4617219089Spjd * inputs: 4618219089Spjd * zc_name name of filesystem 4619219089Spjd * zc_value prefix name for snapshot 4620219089Spjd * zc_cleanup_fd cleanup-on-exit file descriptor for calling process 4621219089Spjd * 4622219089Spjd * outputs: 4623219089Spjd */ 4624219089Spjdstatic int 4625219089Spjdzfs_ioc_tmp_snapshot(zfs_cmd_t *zc) 4626219089Spjd{ 4627219089Spjd char *snap_name; 4628219089Spjd int error; 4629219089Spjd 4630219089Spjd snap_name = kmem_asprintf("%s-%016llx", zc->zc_value, 4631219089Spjd (u_longlong_t)ddi_get_lbolt64()); 4632219089Spjd 4633219089Spjd if (strlen(snap_name) >= MAXNAMELEN) { 4634219089Spjd strfree(snap_name); 4635219089Spjd return (E2BIG); 4636219089Spjd } 4637219089Spjd 4638219089Spjd error = dmu_objset_snapshot(zc->zc_name, snap_name, snap_name, 4639219089Spjd NULL, B_FALSE, B_TRUE, zc->zc_cleanup_fd); 4640219089Spjd if (error != 0) { 4641219089Spjd strfree(snap_name); 4642219089Spjd return (error); 4643219089Spjd } 4644219089Spjd 4645219089Spjd (void) strcpy(zc->zc_value, snap_name); 4646219089Spjd strfree(snap_name); 4647219089Spjd return (0); 4648219089Spjd} 4649219089Spjd 4650219089Spjd/* 4651219089Spjd * inputs: 4652219089Spjd * zc_name name of "to" snapshot 4653219089Spjd * zc_value name of "from" snapshot 4654219089Spjd * zc_cookie file descriptor to write diff data on 4655219089Spjd * 4656219089Spjd * outputs: 4657219089Spjd * dmu_diff_record_t's to the file descriptor 4658219089Spjd */ 4659219089Spjdstatic int 4660219089Spjdzfs_ioc_diff(zfs_cmd_t *zc) 4661219089Spjd{ 4662219089Spjd objset_t *fromsnap; 4663219089Spjd objset_t *tosnap; 4664219089Spjd file_t *fp; 4665219089Spjd offset_t off; 4666219089Spjd int error; 4667219089Spjd 4668219089Spjd error = dmu_objset_hold(zc->zc_name, FTAG, &tosnap); 4669219089Spjd if (error) 4670219089Spjd return (error); 4671219089Spjd 4672219089Spjd error = dmu_objset_hold(zc->zc_value, FTAG, &fromsnap); 4673219089Spjd if (error) { 4674219089Spjd dmu_objset_rele(tosnap, FTAG); 4675219089Spjd return (error); 4676219089Spjd } 4677219089Spjd 4678247602Spjd fp = getf(zc->zc_cookie, CAP_WRITE); 4679219089Spjd if (fp == NULL) { 4680219089Spjd dmu_objset_rele(fromsnap, FTAG); 4681219089Spjd dmu_objset_rele(tosnap, FTAG); 4682219089Spjd return (EBADF); 4683219089Spjd } 4684219089Spjd 4685219089Spjd off = fp->f_offset; 4686219089Spjd 4687219089Spjd error = dmu_diff(tosnap, fromsnap, fp, &off); 4688219089Spjd 4689219089Spjd if (off >= 0 && off <= MAXOFFSET_T) 4690219089Spjd fp->f_offset = off; 4691219089Spjd releasef(zc->zc_cookie); 4692219089Spjd 4693219089Spjd dmu_objset_rele(fromsnap, FTAG); 4694219089Spjd dmu_objset_rele(tosnap, FTAG); 4695219089Spjd return (error); 4696219089Spjd} 4697219089Spjd 4698209962Smm#ifdef sun 4699185029Spjd/* 4700209962Smm * Remove all ACL files in shares dir 4701209962Smm */ 4702209962Smmstatic int 4703209962Smmzfs_smb_acl_purge(znode_t *dzp) 4704209962Smm{ 4705209962Smm zap_cursor_t zc; 4706209962Smm zap_attribute_t zap; 4707209962Smm zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 4708209962Smm int error; 4709209962Smm 4710209962Smm for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 4711209962Smm (error = zap_cursor_retrieve(&zc, &zap)) == 0; 4712209962Smm zap_cursor_advance(&zc)) { 4713209962Smm if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 4714209962Smm NULL, 0)) != 0) 4715209962Smm break; 4716209962Smm } 4717209962Smm zap_cursor_fini(&zc); 4718209962Smm return (error); 4719209962Smm} 4720209962Smm#endif /* sun */ 4721209962Smm 4722209962Smmstatic int 4723209962Smmzfs_ioc_smb_acl(zfs_cmd_t *zc) 4724209962Smm{ 4725209962Smm#ifdef sun 4726209962Smm vnode_t *vp; 4727209962Smm znode_t *dzp; 4728209962Smm vnode_t *resourcevp = NULL; 4729209962Smm znode_t *sharedir; 4730209962Smm zfsvfs_t *zfsvfs; 4731209962Smm nvlist_t *nvlist; 4732209962Smm char *src, *target; 4733209962Smm vattr_t vattr; 4734209962Smm vsecattr_t vsec; 4735209962Smm int error = 0; 4736209962Smm 4737209962Smm if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 4738209962Smm NO_FOLLOW, NULL, &vp)) != 0) 4739209962Smm return (error); 4740209962Smm 4741209962Smm /* Now make sure mntpnt and dataset are ZFS */ 4742209962Smm 4743219089Spjd if (strcmp(vp->v_vfsp->mnt_stat.f_fstypename, "zfs") != 0 || 4744209962Smm (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 4745209962Smm zc->zc_name) != 0)) { 4746209962Smm VN_RELE(vp); 4747209962Smm return (EINVAL); 4748209962Smm } 4749209962Smm 4750209962Smm dzp = VTOZ(vp); 4751209962Smm zfsvfs = dzp->z_zfsvfs; 4752209962Smm ZFS_ENTER(zfsvfs); 4753209962Smm 4754209962Smm /* 4755209962Smm * Create share dir if its missing. 4756209962Smm */ 4757209962Smm mutex_enter(&zfsvfs->z_lock); 4758209962Smm if (zfsvfs->z_shares_dir == 0) { 4759209962Smm dmu_tx_t *tx; 4760209962Smm 4761209962Smm tx = dmu_tx_create(zfsvfs->z_os); 4762209962Smm dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 4763209962Smm ZFS_SHARES_DIR); 4764209962Smm dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 4765209962Smm error = dmu_tx_assign(tx, TXG_WAIT); 4766209962Smm if (error) { 4767209962Smm dmu_tx_abort(tx); 4768209962Smm } else { 4769209962Smm error = zfs_create_share_dir(zfsvfs, tx); 4770209962Smm dmu_tx_commit(tx); 4771209962Smm } 4772209962Smm if (error) { 4773209962Smm mutex_exit(&zfsvfs->z_lock); 4774209962Smm VN_RELE(vp); 4775209962Smm ZFS_EXIT(zfsvfs); 4776209962Smm return (error); 4777209962Smm } 4778209962Smm } 4779209962Smm mutex_exit(&zfsvfs->z_lock); 4780209962Smm 4781209962Smm ASSERT(zfsvfs->z_shares_dir); 4782209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 4783209962Smm VN_RELE(vp); 4784209962Smm ZFS_EXIT(zfsvfs); 4785209962Smm return (error); 4786209962Smm } 4787209962Smm 4788209962Smm switch (zc->zc_cookie) { 4789209962Smm case ZFS_SMB_ACL_ADD: 4790209962Smm vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 4791209962Smm vattr.va_type = VREG; 4792209962Smm vattr.va_mode = S_IFREG|0777; 4793209962Smm vattr.va_uid = 0; 4794209962Smm vattr.va_gid = 0; 4795209962Smm 4796209962Smm vsec.vsa_mask = VSA_ACE; 4797209962Smm vsec.vsa_aclentp = &full_access; 4798209962Smm vsec.vsa_aclentsz = sizeof (full_access); 4799209962Smm vsec.vsa_aclcnt = 1; 4800209962Smm 4801209962Smm error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 4802209962Smm &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 4803209962Smm if (resourcevp) 4804209962Smm VN_RELE(resourcevp); 4805209962Smm break; 4806209962Smm 4807209962Smm case ZFS_SMB_ACL_REMOVE: 4808209962Smm error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 4809209962Smm NULL, 0); 4810209962Smm break; 4811209962Smm 4812209962Smm case ZFS_SMB_ACL_RENAME: 4813209962Smm if ((error = get_nvlist(zc->zc_nvlist_src, 4814219089Spjd zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { 4815209962Smm VN_RELE(vp); 4816209962Smm ZFS_EXIT(zfsvfs); 4817209962Smm return (error); 4818209962Smm } 4819209962Smm if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 4820209962Smm nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 4821209962Smm &target)) { 4822209962Smm VN_RELE(vp); 4823209962Smm VN_RELE(ZTOV(sharedir)); 4824209962Smm ZFS_EXIT(zfsvfs); 4825219089Spjd nvlist_free(nvlist); 4826209962Smm return (error); 4827209962Smm } 4828209962Smm error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 4829209962Smm kcred, NULL, 0); 4830209962Smm nvlist_free(nvlist); 4831209962Smm break; 4832209962Smm 4833209962Smm case ZFS_SMB_ACL_PURGE: 4834209962Smm error = zfs_smb_acl_purge(sharedir); 4835209962Smm break; 4836209962Smm 4837209962Smm default: 4838209962Smm error = EINVAL; 4839209962Smm break; 4840209962Smm } 4841209962Smm 4842209962Smm VN_RELE(vp); 4843209962Smm VN_RELE(ZTOV(sharedir)); 4844209962Smm 4845209962Smm ZFS_EXIT(zfsvfs); 4846209962Smm 4847209962Smm return (error); 4848209962Smm#else /* !sun */ 4849209962Smm return (EOPNOTSUPP); 4850209962Smm#endif /* !sun */ 4851209962Smm} 4852209962Smm 4853209962Smm/* 4854219089Spjd * inputs: 4855219089Spjd * zc_name name of filesystem 4856219089Spjd * zc_value short name of snap 4857219089Spjd * zc_string user-supplied tag for this hold 4858219089Spjd * zc_cookie recursive flag 4859219089Spjd * zc_temphold set if hold is temporary 4860219089Spjd * zc_cleanup_fd cleanup-on-exit file descriptor for calling process 4861219089Spjd * zc_sendobj if non-zero, the objid for zc_name@zc_value 4862219089Spjd * zc_createtxg if zc_sendobj is non-zero, snap must have zc_createtxg 4863219089Spjd * 4864219089Spjd * outputs: none 4865219089Spjd */ 4866219089Spjdstatic int 4867219089Spjdzfs_ioc_hold(zfs_cmd_t *zc) 4868219089Spjd{ 4869219089Spjd boolean_t recursive = zc->zc_cookie; 4870219089Spjd spa_t *spa; 4871219089Spjd dsl_pool_t *dp; 4872219089Spjd dsl_dataset_t *ds; 4873219089Spjd int error; 4874219089Spjd minor_t minor = 0; 4875219089Spjd 4876219089Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 4877219089Spjd return (EINVAL); 4878219089Spjd 4879219089Spjd if (zc->zc_sendobj == 0) { 4880219089Spjd return (dsl_dataset_user_hold(zc->zc_name, zc->zc_value, 4881219089Spjd zc->zc_string, recursive, zc->zc_temphold, 4882219089Spjd zc->zc_cleanup_fd)); 4883219089Spjd } 4884219089Spjd 4885219089Spjd if (recursive) 4886219089Spjd return (EINVAL); 4887219089Spjd 4888219089Spjd error = spa_open(zc->zc_name, &spa, FTAG); 4889219089Spjd if (error) 4890219089Spjd return (error); 4891219089Spjd 4892219089Spjd dp = spa_get_dsl(spa); 4893219089Spjd rw_enter(&dp->dp_config_rwlock, RW_READER); 4894219089Spjd error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 4895219089Spjd rw_exit(&dp->dp_config_rwlock); 4896219089Spjd spa_close(spa, FTAG); 4897219089Spjd if (error) 4898219089Spjd return (error); 4899219089Spjd 4900219089Spjd /* 4901219089Spjd * Until we have a hold on this snapshot, it's possible that 4902219089Spjd * zc_sendobj could've been destroyed and reused as part 4903219089Spjd * of a later txg. Make sure we're looking at the right object. 4904219089Spjd */ 4905219089Spjd if (zc->zc_createtxg != ds->ds_phys->ds_creation_txg) { 4906219089Spjd dsl_dataset_rele(ds, FTAG); 4907219089Spjd return (ENOENT); 4908219089Spjd } 4909219089Spjd 4910219089Spjd if (zc->zc_cleanup_fd != -1 && zc->zc_temphold) { 4911219089Spjd error = zfs_onexit_fd_hold(zc->zc_cleanup_fd, &minor); 4912219089Spjd if (error) { 4913219089Spjd dsl_dataset_rele(ds, FTAG); 4914219089Spjd return (error); 4915219089Spjd } 4916219089Spjd } 4917219089Spjd 4918219089Spjd error = dsl_dataset_user_hold_for_send(ds, zc->zc_string, 4919219089Spjd zc->zc_temphold); 4920219089Spjd if (minor != 0) { 4921219089Spjd if (error == 0) { 4922219089Spjd dsl_register_onexit_hold_cleanup(ds, zc->zc_string, 4923219089Spjd minor); 4924219089Spjd } 4925219089Spjd zfs_onexit_fd_rele(zc->zc_cleanup_fd); 4926219089Spjd } 4927219089Spjd dsl_dataset_rele(ds, FTAG); 4928219089Spjd 4929219089Spjd return (error); 4930219089Spjd} 4931219089Spjd 4932219089Spjd/* 4933219089Spjd * inputs: 4934219089Spjd * zc_name name of dataset from which we're releasing a user hold 4935219089Spjd * zc_value short name of snap 4936219089Spjd * zc_string user-supplied tag for this hold 4937219089Spjd * zc_cookie recursive flag 4938219089Spjd * 4939219089Spjd * outputs: none 4940219089Spjd */ 4941219089Spjdstatic int 4942219089Spjdzfs_ioc_release(zfs_cmd_t *zc) 4943219089Spjd{ 4944219089Spjd boolean_t recursive = zc->zc_cookie; 4945219089Spjd 4946219089Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 4947219089Spjd return (EINVAL); 4948219089Spjd 4949219089Spjd return (dsl_dataset_user_release(zc->zc_name, zc->zc_value, 4950219089Spjd zc->zc_string, recursive)); 4951219089Spjd} 4952219089Spjd 4953219089Spjd/* 4954219089Spjd * inputs: 4955219089Spjd * zc_name name of filesystem 4956219089Spjd * 4957219089Spjd * outputs: 4958219089Spjd * zc_nvlist_src{_size} nvlist of snapshot holds 4959219089Spjd */ 4960219089Spjdstatic int 4961219089Spjdzfs_ioc_get_holds(zfs_cmd_t *zc) 4962219089Spjd{ 4963219089Spjd nvlist_t *nvp; 4964219089Spjd int error; 4965219089Spjd 4966219089Spjd if ((error = dsl_dataset_get_holds(zc->zc_name, &nvp)) == 0) { 4967219089Spjd error = put_nvlist(zc, nvp); 4968219089Spjd nvlist_free(nvp); 4969219089Spjd } 4970219089Spjd 4971219089Spjd return (error); 4972219089Spjd} 4973219089Spjd 4974219089Spjd/* 4975228103Smm * inputs: 4976228103Smm * zc_name name of new filesystem or snapshot 4977228103Smm * zc_value full name of old snapshot 4978228103Smm * 4979228103Smm * outputs: 4980228103Smm * zc_cookie space in bytes 4981228103Smm * zc_objset_type compressed space in bytes 4982228103Smm * zc_perm_action uncompressed space in bytes 4983228103Smm */ 4984228103Smmstatic int 4985228103Smmzfs_ioc_space_written(zfs_cmd_t *zc) 4986228103Smm{ 4987228103Smm int error; 4988228103Smm dsl_dataset_t *new, *old; 4989228103Smm 4990228103Smm error = dsl_dataset_hold(zc->zc_name, FTAG, &new); 4991228103Smm if (error != 0) 4992228103Smm return (error); 4993228103Smm error = dsl_dataset_hold(zc->zc_value, FTAG, &old); 4994228103Smm if (error != 0) { 4995228103Smm dsl_dataset_rele(new, FTAG); 4996228103Smm return (error); 4997228103Smm } 4998228103Smm 4999228103Smm error = dsl_dataset_space_written(old, new, &zc->zc_cookie, 5000228103Smm &zc->zc_objset_type, &zc->zc_perm_action); 5001228103Smm dsl_dataset_rele(old, FTAG); 5002228103Smm dsl_dataset_rele(new, FTAG); 5003228103Smm return (error); 5004228103Smm} 5005228103Smm 5006228103Smm/* 5007228103Smm * inputs: 5008228103Smm * zc_name full name of last snapshot 5009228103Smm * zc_value full name of first snapshot 5010228103Smm * 5011228103Smm * outputs: 5012228103Smm * zc_cookie space in bytes 5013228103Smm * zc_objset_type compressed space in bytes 5014228103Smm * zc_perm_action uncompressed space in bytes 5015228103Smm */ 5016228103Smmstatic int 5017228103Smmzfs_ioc_space_snaps(zfs_cmd_t *zc) 5018228103Smm{ 5019228103Smm int error; 5020228103Smm dsl_dataset_t *new, *old; 5021228103Smm 5022228103Smm error = dsl_dataset_hold(zc->zc_name, FTAG, &new); 5023228103Smm if (error != 0) 5024228103Smm return (error); 5025228103Smm error = dsl_dataset_hold(zc->zc_value, FTAG, &old); 5026228103Smm if (error != 0) { 5027228103Smm dsl_dataset_rele(new, FTAG); 5028228103Smm return (error); 5029228103Smm } 5030228103Smm 5031228103Smm error = dsl_dataset_space_wouldfree(old, new, &zc->zc_cookie, 5032228103Smm &zc->zc_objset_type, &zc->zc_perm_action); 5033228103Smm dsl_dataset_rele(old, FTAG); 5034228103Smm dsl_dataset_rele(new, FTAG); 5035228103Smm return (error); 5036228103Smm} 5037228103Smm 5038228103Smm/* 5039185029Spjd * pool create, destroy, and export don't log the history as part of 5040185029Spjd * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export 5041185029Spjd * do the logging of those commands. 5042185029Spjd */ 5043185029Spjdstatic int 5044168404Spjdzfs_ioc_jail(zfs_cmd_t *zc) 5045168404Spjd{ 5046168404Spjd 5047185029Spjd return (zone_dataset_attach(curthread->td_ucred, zc->zc_name, 5048185029Spjd (int)zc->zc_jailid)); 5049168404Spjd} 5050168404Spjd 5051168404Spjdstatic int 5052168404Spjdzfs_ioc_unjail(zfs_cmd_t *zc) 5053168404Spjd{ 5054168404Spjd 5055185029Spjd return (zone_dataset_detach(curthread->td_ucred, zc->zc_name, 5056185029Spjd (int)zc->zc_jailid)); 5057168404Spjd} 5058168404Spjd 5059168404Spjdstatic zfs_ioc_vec_t zfs_ioc_vec[] = { 5060209962Smm { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE, 5061246688Smm POOL_CHECK_NONE }, 5062209962Smm { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE, 5063246688Smm POOL_CHECK_NONE }, 5064209962Smm { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5065246688Smm POOL_CHECK_NONE }, 5066209962Smm { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE, 5067246688Smm POOL_CHECK_NONE }, 5068209962Smm { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE, 5069246688Smm POOL_CHECK_NONE }, 5070209962Smm { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE, 5071246688Smm POOL_CHECK_NONE }, 5072209962Smm { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE, 5073246688Smm POOL_CHECK_NONE }, 5074219089Spjd { zfs_ioc_pool_scan, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5075246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5076209962Smm { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, 5077246688Smm POOL_CHECK_READONLY }, 5078209962Smm { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5079246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5080209962Smm { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE, 5081246688Smm POOL_CHECK_NONE }, 5082209962Smm { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5083246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5084209962Smm { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5085246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5086209962Smm { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5087246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5088209962Smm { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5089246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5090209962Smm { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5091246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5092209962Smm { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE, 5093246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5094219089Spjd { zfs_ioc_vdev_setfru, zfs_secpolicy_config, POOL_NAME, B_FALSE, 5095246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5096209962Smm { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5097246688Smm POOL_CHECK_SUSPENDED }, 5098209962Smm { zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5099246688Smm POOL_CHECK_NONE }, 5100209962Smm { zfs_ioc_dataset_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5101246688Smm POOL_CHECK_SUSPENDED }, 5102209962Smm { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5103246688Smm POOL_CHECK_SUSPENDED }, 5104246688Smm { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, 5105246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5106246688Smm { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, 5107246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5108209962Smm { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE, 5109246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY}, 5110209962Smm { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE, 5111246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5112246688Smm { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE, 5113246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5114246688Smm { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE, 5115246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5116246688Smm { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_FALSE, 5117246688Smm POOL_CHECK_NONE }, 5118209962Smm { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 5119246688Smm POOL_CHECK_NONE }, 5120209962Smm { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE, 5121246688Smm POOL_CHECK_NONE }, 5122209962Smm { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE, 5123246688Smm POOL_CHECK_NONE }, 5124209962Smm { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE, 5125246688Smm POOL_CHECK_NONE }, 5126246688Smm { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5127246688Smm POOL_CHECK_NONE }, 5128209962Smm { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE, 5129246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5130246688Smm { zfs_ioc_destroy_snaps_nvl, zfs_secpolicy_destroy_recursive, 5131246688Smm DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5132209962Smm { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE, 5133246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5134219089Spjd { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_diff, POOL_NAME, B_FALSE, 5135246688Smm POOL_CHECK_NONE }, 5136219089Spjd { zfs_ioc_obj_to_path, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, 5137246688Smm POOL_CHECK_SUSPENDED }, 5138209962Smm { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5139246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5140209962Smm { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE, 5141246688Smm POOL_CHECK_NONE }, 5142209962Smm { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE, 5143246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5144209962Smm { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5145246688Smm POOL_CHECK_NONE }, 5146246688Smm { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE, 5147246688Smm POOL_CHECK_NONE }, 5148209962Smm { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE, 5149246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5150209962Smm { zfs_ioc_smb_acl, zfs_secpolicy_smb_acl, DATASET_NAME, B_FALSE, 5151246688Smm POOL_CHECK_NONE }, 5152246688Smm { zfs_ioc_userspace_one, zfs_secpolicy_userspace_one, DATASET_NAME, 5153246688Smm B_FALSE, POOL_CHECK_NONE }, 5154246688Smm { zfs_ioc_userspace_many, zfs_secpolicy_userspace_many, DATASET_NAME, 5155246688Smm B_FALSE, POOL_CHECK_NONE }, 5156209962Smm { zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 5157246688Smm DATASET_NAME, B_FALSE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5158246688Smm { zfs_ioc_hold, zfs_secpolicy_hold, DATASET_NAME, B_TRUE, 5159246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5160219089Spjd { zfs_ioc_release, zfs_secpolicy_release, DATASET_NAME, B_TRUE, 5161246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5162219089Spjd { zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5163246688Smm POOL_CHECK_SUSPENDED }, 5164219089Spjd { zfs_ioc_objset_recvd_props, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5165246688Smm POOL_CHECK_NONE }, 5166219089Spjd { zfs_ioc_vdev_split, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5167246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5168219089Spjd { zfs_ioc_next_obj, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5169246688Smm POOL_CHECK_NONE }, 5170246688Smm { zfs_ioc_diff, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, 5171246688Smm POOL_CHECK_NONE }, 5172219089Spjd { zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot, DATASET_NAME, 5173246688Smm B_FALSE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5174219089Spjd { zfs_ioc_obj_to_stats, zfs_secpolicy_diff, DATASET_NAME, B_FALSE, 5175246688Smm POOL_CHECK_SUSPENDED }, 5176246688Smm { zfs_ioc_jail, zfs_secpolicy_config, DATASET_NAME, B_TRUE, 5177246688Smm POOL_CHECK_NONE }, 5178246688Smm { zfs_ioc_unjail, zfs_secpolicy_config, DATASET_NAME, B_TRUE, 5179246688Smm POOL_CHECK_NONE }, 5180228103Smm { zfs_ioc_pool_reguid, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5181246688Smm POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }, 5182228103Smm { zfs_ioc_space_written, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5183246688Smm POOL_CHECK_SUSPENDED }, 5184228103Smm { zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5185246688Smm POOL_CHECK_SUSPENDED }, 5186235222Smm { zfs_ioc_send_progress, zfs_secpolicy_read, DATASET_NAME, B_FALSE, 5187246688Smm POOL_CHECK_NONE }, 5188236155Smm { zfs_ioc_pool_reopen, zfs_secpolicy_config, POOL_NAME, B_TRUE, 5189246688Smm POOL_CHECK_SUSPENDED }, 5190168404Spjd}; 5191168404Spjd 5192209962Smmint 5193246688Smmpool_status_check(const char *name, zfs_ioc_namecheck_t type, 5194246688Smm zfs_ioc_poolcheck_t check) 5195209962Smm{ 5196209962Smm spa_t *spa; 5197209962Smm int error; 5198209962Smm 5199209962Smm ASSERT(type == POOL_NAME || type == DATASET_NAME); 5200209962Smm 5201246688Smm if (check & POOL_CHECK_NONE) 5202246688Smm return (0); 5203246688Smm 5204209962Smm error = spa_open(name, &spa, FTAG); 5205209962Smm if (error == 0) { 5206246688Smm if ((check & POOL_CHECK_SUSPENDED) && spa_suspended(spa)) 5207209962Smm error = EAGAIN; 5208246688Smm else if ((check & POOL_CHECK_READONLY) && !spa_writeable(spa)) 5209246688Smm error = EROFS; 5210209962Smm spa_close(spa, FTAG); 5211209962Smm } 5212209962Smm return (error); 5213209962Smm} 5214209962Smm 5215219089Spjd/* 5216219089Spjd * Find a free minor number. 5217219089Spjd */ 5218219089Spjdminor_t 5219219089Spjdzfsdev_minor_alloc(void) 5220219089Spjd{ 5221219089Spjd static minor_t last_minor; 5222219089Spjd minor_t m; 5223219089Spjd 5224224791Spjd ASSERT(MUTEX_HELD(&spa_namespace_lock)); 5225219089Spjd 5226219089Spjd for (m = last_minor + 1; m != last_minor; m++) { 5227219089Spjd if (m > ZFSDEV_MAX_MINOR) 5228219089Spjd m = 1; 5229219089Spjd if (ddi_get_soft_state(zfsdev_state, m) == NULL) { 5230219089Spjd last_minor = m; 5231219089Spjd return (m); 5232219089Spjd } 5233219089Spjd } 5234219089Spjd 5235219089Spjd return (0); 5236219089Spjd} 5237219089Spjd 5238168404Spjdstatic int 5239219089Spjdzfs_ctldev_init(struct cdev *devp) 5240219089Spjd{ 5241219089Spjd minor_t minor; 5242219089Spjd zfs_soft_state_t *zs; 5243219089Spjd 5244224791Spjd ASSERT(MUTEX_HELD(&spa_namespace_lock)); 5245219089Spjd 5246219089Spjd minor = zfsdev_minor_alloc(); 5247219089Spjd if (minor == 0) 5248219089Spjd return (ENXIO); 5249219089Spjd 5250219089Spjd if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) 5251219089Spjd return (EAGAIN); 5252219089Spjd 5253219089Spjd devfs_set_cdevpriv((void *)(uintptr_t)minor, zfsdev_close); 5254219089Spjd 5255219089Spjd zs = ddi_get_soft_state(zfsdev_state, minor); 5256219089Spjd zs->zss_type = ZSST_CTLDEV; 5257219089Spjd zfs_onexit_init((zfs_onexit_t **)&zs->zss_data); 5258219089Spjd 5259219089Spjd return (0); 5260219089Spjd} 5261219089Spjd 5262219089Spjdstatic void 5263219089Spjdzfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor) 5264219089Spjd{ 5265224791Spjd ASSERT(MUTEX_HELD(&spa_namespace_lock)); 5266219089Spjd 5267219089Spjd zfs_onexit_destroy(zo); 5268219089Spjd ddi_soft_state_free(zfsdev_state, minor); 5269219089Spjd} 5270219089Spjd 5271219089Spjdvoid * 5272219089Spjdzfsdev_get_soft_state(minor_t minor, enum zfs_soft_state_type which) 5273219089Spjd{ 5274219089Spjd zfs_soft_state_t *zp; 5275219089Spjd 5276219089Spjd zp = ddi_get_soft_state(zfsdev_state, minor); 5277219089Spjd if (zp == NULL || zp->zss_type != which) 5278219089Spjd return (NULL); 5279219089Spjd 5280219089Spjd return (zp->zss_data); 5281219089Spjd} 5282219089Spjd 5283219089Spjdstatic int 5284219089Spjdzfsdev_open(struct cdev *devp, int flag, int mode, struct thread *td) 5285219089Spjd{ 5286219089Spjd int error = 0; 5287219089Spjd 5288219089Spjd#ifdef sun 5289219089Spjd if (getminor(*devp) != 0) 5290219089Spjd return (zvol_open(devp, flag, otyp, cr)); 5291219089Spjd#endif 5292219089Spjd 5293219089Spjd /* This is the control device. Allocate a new minor if requested. */ 5294219089Spjd if (flag & FEXCL) { 5295224791Spjd mutex_enter(&spa_namespace_lock); 5296219089Spjd error = zfs_ctldev_init(devp); 5297224791Spjd mutex_exit(&spa_namespace_lock); 5298219089Spjd } 5299219089Spjd 5300219089Spjd return (error); 5301219089Spjd} 5302219089Spjd 5303219089Spjdstatic void 5304219089Spjdzfsdev_close(void *data) 5305219089Spjd{ 5306219089Spjd zfs_onexit_t *zo; 5307219089Spjd minor_t minor = (minor_t)(uintptr_t)data; 5308219089Spjd 5309219089Spjd if (minor == 0) 5310219089Spjd return; 5311219089Spjd 5312224791Spjd mutex_enter(&spa_namespace_lock); 5313219089Spjd zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); 5314219089Spjd if (zo == NULL) { 5315224791Spjd mutex_exit(&spa_namespace_lock); 5316219089Spjd return; 5317219089Spjd } 5318219089Spjd zfs_ctldev_destroy(zo, minor); 5319224791Spjd mutex_exit(&spa_namespace_lock); 5320219089Spjd} 5321219089Spjd 5322219089Spjdstatic int 5323168404Spjdzfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 5324168404Spjd struct thread *td) 5325168404Spjd{ 5326219089Spjd zfs_cmd_t *zc; 5327168404Spjd uint_t vec; 5328219089Spjd int cflag, error, len; 5329168404Spjd 5330219089Spjd cflag = ZFS_CMD_COMPAT_NONE; 5331219089Spjd len = IOCPARM_LEN(cmd); 5332219089Spjd 5333214854Sdelphij /* 5334247540Smm * Check if we are talking to supported older binaries 5335247540Smm * and translate zfs_cmd if necessary 5336214854Sdelphij */ 5337219089Spjd if (len < sizeof(zfs_cmd_t)) 5338247540Smm if (len == sizeof(zfs_cmd_v28_t)) { 5339247540Smm cflag = ZFS_CMD_COMPAT_V28; 5340247540Smm vec = ZFS_IOC(cmd); 5341247540Smm } else if (len == sizeof(zfs_cmd_v15_t)) { 5342219089Spjd cflag = ZFS_CMD_COMPAT_V15; 5343219089Spjd vec = zfs_ioctl_v15_to_v28[ZFS_IOC(cmd)]; 5344219089Spjd } else 5345219089Spjd return (EINVAL); 5346219089Spjd else 5347219089Spjd vec = ZFS_IOC(cmd); 5348214854Sdelphij 5349219089Spjd if (cflag != ZFS_CMD_COMPAT_NONE) { 5350219089Spjd if (vec == ZFS_IOC_COMPAT_PASS) 5351219089Spjd return (0); 5352219089Spjd else if (vec == ZFS_IOC_COMPAT_FAIL) 5353219089Spjd return (ENOTSUP); 5354219089Spjd } 5355168404Spjd 5356247540Smm /* 5357247540Smm * Check if we have sufficient kernel memory allocated 5358247540Smm * for the zfs_cmd_t request. Bail out if not so we 5359247540Smm * will not access undefined memory region. 5360247540Smm */ 5361168404Spjd if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 5362168404Spjd return (EINVAL); 5363168404Spjd 5364219089Spjd if (cflag != ZFS_CMD_COMPAT_NONE) { 5365219089Spjd zc = kmem_zalloc(sizeof(zfs_cmd_t), KM_SLEEP); 5366219089Spjd bzero(zc, sizeof(zfs_cmd_t)); 5367219089Spjd zfs_cmd_compat_get(zc, addr, cflag); 5368219089Spjd zfs_ioctl_compat_pre(zc, &vec, cflag); 5369219089Spjd } else { 5370219089Spjd zc = (void *)addr; 5371219089Spjd } 5372219089Spjd 5373185029Spjd error = zfs_ioc_vec[vec].zvec_secpolicy(zc, td->td_ucred); 5374168404Spjd 5375168404Spjd /* 5376168404Spjd * Ensure that all pool/dataset names are valid before we pass down to 5377168404Spjd * the lower layers. 5378168404Spjd */ 5379168404Spjd if (error == 0) { 5380168404Spjd zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 5381219089Spjd zc->zc_iflags = flag & FKIOCTL; 5382168404Spjd switch (zfs_ioc_vec[vec].zvec_namecheck) { 5383185029Spjd case POOL_NAME: 5384168404Spjd if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 5385168404Spjd error = EINVAL; 5386246688Smm else 5387209962Smm error = pool_status_check(zc->zc_name, 5388246688Smm zfs_ioc_vec[vec].zvec_namecheck, 5389246688Smm zfs_ioc_vec[vec].zvec_pool_check); 5390168404Spjd break; 5391168404Spjd 5392185029Spjd case DATASET_NAME: 5393168404Spjd if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 5394168404Spjd error = EINVAL; 5395246688Smm else 5396209962Smm error = pool_status_check(zc->zc_name, 5397246688Smm zfs_ioc_vec[vec].zvec_namecheck, 5398246688Smm zfs_ioc_vec[vec].zvec_pool_check); 5399168404Spjd break; 5400168404Spjd 5401185029Spjd case NO_NAME: 5402168404Spjd break; 5403168404Spjd } 5404168404Spjd } 5405168404Spjd 5406168404Spjd if (error == 0) 5407168404Spjd error = zfs_ioc_vec[vec].zvec_func(zc); 5408168404Spjd 5409196985Spjd if (error == 0) { 5410209962Smm if (zfs_ioc_vec[vec].zvec_his_log) 5411196985Spjd zfs_log_history(zc); 5412196985Spjd } 5413185029Spjd 5414219089Spjd if (cflag != ZFS_CMD_COMPAT_NONE) { 5415219089Spjd zfs_ioctl_compat_post(zc, ZFS_IOC(cmd), cflag); 5416219089Spjd zfs_cmd_compat_put(zc, addr, cflag); 5417219089Spjd kmem_free(zc, sizeof(zfs_cmd_t)); 5418219089Spjd } 5419219089Spjd 5420168404Spjd return (error); 5421168404Spjd} 5422168404Spjd 5423219089Spjd#ifdef sun 5424219089Spjdstatic int 5425219089Spjdzfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5426219089Spjd{ 5427219089Spjd if (cmd != DDI_ATTACH) 5428219089Spjd return (DDI_FAILURE); 5429219089Spjd 5430219089Spjd if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 5431219089Spjd DDI_PSEUDO, 0) == DDI_FAILURE) 5432219089Spjd return (DDI_FAILURE); 5433219089Spjd 5434219089Spjd zfs_dip = dip; 5435219089Spjd 5436219089Spjd ddi_report_dev(dip); 5437219089Spjd 5438219089Spjd return (DDI_SUCCESS); 5439219089Spjd} 5440219089Spjd 5441219089Spjdstatic int 5442219089Spjdzfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5443219089Spjd{ 5444219089Spjd if (spa_busy() || zfs_busy() || zvol_busy()) 5445219089Spjd return (DDI_FAILURE); 5446219089Spjd 5447219089Spjd if (cmd != DDI_DETACH) 5448219089Spjd return (DDI_FAILURE); 5449219089Spjd 5450219089Spjd zfs_dip = NULL; 5451219089Spjd 5452219089Spjd ddi_prop_remove_all(dip); 5453219089Spjd ddi_remove_minor_node(dip, NULL); 5454219089Spjd 5455219089Spjd return (DDI_SUCCESS); 5456219089Spjd} 5457219089Spjd 5458219089Spjd/*ARGSUSED*/ 5459219089Spjdstatic int 5460219089Spjdzfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 5461219089Spjd{ 5462219089Spjd switch (infocmd) { 5463219089Spjd case DDI_INFO_DEVT2DEVINFO: 5464219089Spjd *result = zfs_dip; 5465219089Spjd return (DDI_SUCCESS); 5466219089Spjd 5467219089Spjd case DDI_INFO_DEVT2INSTANCE: 5468219089Spjd *result = (void *)0; 5469219089Spjd return (DDI_SUCCESS); 5470219089Spjd } 5471219089Spjd 5472219089Spjd return (DDI_FAILURE); 5473219089Spjd} 5474219089Spjd#endif /* sun */ 5475219089Spjd 5476168404Spjd/* 5477168404Spjd * OK, so this is a little weird. 5478168404Spjd * 5479168404Spjd * /dev/zfs is the control node, i.e. minor 0. 5480168404Spjd * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 5481168404Spjd * 5482168404Spjd * /dev/zfs has basically nothing to do except serve up ioctls, 5483168404Spjd * so most of the standard driver entry points are in zvol.c. 5484168404Spjd */ 5485219089Spjd#ifdef sun 5486219089Spjdstatic struct cb_ops zfs_cb_ops = { 5487219089Spjd zfsdev_open, /* open */ 5488219089Spjd zfsdev_close, /* close */ 5489219089Spjd zvol_strategy, /* strategy */ 5490219089Spjd nodev, /* print */ 5491219089Spjd zvol_dump, /* dump */ 5492219089Spjd zvol_read, /* read */ 5493219089Spjd zvol_write, /* write */ 5494219089Spjd zfsdev_ioctl, /* ioctl */ 5495219089Spjd nodev, /* devmap */ 5496219089Spjd nodev, /* mmap */ 5497219089Spjd nodev, /* segmap */ 5498219089Spjd nochpoll, /* poll */ 5499219089Spjd ddi_prop_op, /* prop_op */ 5500219089Spjd NULL, /* streamtab */ 5501219089Spjd D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 5502219089Spjd CB_REV, /* version */ 5503219089Spjd nodev, /* async read */ 5504219089Spjd nodev, /* async write */ 5505219089Spjd}; 5506219089Spjd 5507219089Spjdstatic struct dev_ops zfs_dev_ops = { 5508219089Spjd DEVO_REV, /* version */ 5509219089Spjd 0, /* refcnt */ 5510219089Spjd zfs_info, /* info */ 5511219089Spjd nulldev, /* identify */ 5512219089Spjd nulldev, /* probe */ 5513219089Spjd zfs_attach, /* attach */ 5514219089Spjd zfs_detach, /* detach */ 5515219089Spjd nodev, /* reset */ 5516219089Spjd &zfs_cb_ops, /* driver operations */ 5517219089Spjd NULL, /* no bus operations */ 5518219089Spjd NULL, /* power */ 5519219089Spjd ddi_quiesce_not_needed, /* quiesce */ 5520219089Spjd}; 5521219089Spjd 5522219089Spjdstatic struct modldrv zfs_modldrv = { 5523219089Spjd &mod_driverops, 5524219089Spjd "ZFS storage pool", 5525219089Spjd &zfs_dev_ops 5526219089Spjd}; 5527219089Spjd 5528219089Spjdstatic struct modlinkage modlinkage = { 5529219089Spjd MODREV_1, 5530219089Spjd (void *)&zfs_modlfs, 5531219089Spjd (void *)&zfs_modldrv, 5532219089Spjd NULL 5533219089Spjd}; 5534219089Spjd#endif /* sun */ 5535219089Spjd 5536168404Spjdstatic struct cdevsw zfs_cdevsw = { 5537168404Spjd .d_version = D_VERSION, 5538219089Spjd .d_open = zfsdev_open, 5539168404Spjd .d_ioctl = zfsdev_ioctl, 5540168404Spjd .d_name = ZFS_DEV_NAME 5541168404Spjd}; 5542168404Spjd 5543168404Spjdstatic void 5544168404Spjdzfsdev_init(void) 5545168404Spjd{ 5546185029Spjd zfsdev = make_dev(&zfs_cdevsw, 0x0, UID_ROOT, GID_OPERATOR, 0666, 5547168404Spjd ZFS_DEV_NAME); 5548168404Spjd} 5549168404Spjd 5550168404Spjdstatic void 5551168404Spjdzfsdev_fini(void) 5552168404Spjd{ 5553168404Spjd if (zfsdev != NULL) 5554168404Spjd destroy_dev(zfsdev); 5555168404Spjd} 5556168404Spjd 5557169929Spjdstatic struct root_hold_token *zfs_root_token; 5558196458Spjdstruct proc *zfsproc; 5559168404Spjd 5560185029Spjduint_t zfs_fsyncer_key; 5561185029Spjdextern uint_t rrw_tsd_key; 5562185029Spjd 5563219089Spjd#ifdef sun 5564219089Spjdint 5565219089Spjd_init(void) 5566219089Spjd{ 5567219089Spjd int error; 5568219089Spjd 5569219089Spjd spa_init(FREAD | FWRITE); 5570219089Spjd zfs_init(); 5571219089Spjd zvol_init(); 5572219089Spjd 5573219089Spjd if ((error = mod_install(&modlinkage)) != 0) { 5574219089Spjd zvol_fini(); 5575219089Spjd zfs_fini(); 5576219089Spjd spa_fini(); 5577219089Spjd return (error); 5578219089Spjd } 5579219089Spjd 5580219089Spjd tsd_create(&zfs_fsyncer_key, NULL); 5581219089Spjd tsd_create(&rrw_tsd_key, NULL); 5582219089Spjd 5583219089Spjd error = ldi_ident_from_mod(&modlinkage, &zfs_li); 5584219089Spjd ASSERT(error == 0); 5585219089Spjd mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 5586219089Spjd 5587219089Spjd return (0); 5588219089Spjd} 5589219089Spjd 5590219089Spjdint 5591219089Spjd_fini(void) 5592219089Spjd{ 5593219089Spjd int error; 5594219089Spjd 5595219089Spjd if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 5596219089Spjd return (EBUSY); 5597219089Spjd 5598219089Spjd if ((error = mod_remove(&modlinkage)) != 0) 5599219089Spjd return (error); 5600219089Spjd 5601219089Spjd zvol_fini(); 5602219089Spjd zfs_fini(); 5603219089Spjd spa_fini(); 5604219089Spjd if (zfs_nfsshare_inited) 5605219089Spjd (void) ddi_modclose(nfs_mod); 5606219089Spjd if (zfs_smbshare_inited) 5607219089Spjd (void) ddi_modclose(smbsrv_mod); 5608219089Spjd if (zfs_nfsshare_inited || zfs_smbshare_inited) 5609219089Spjd (void) ddi_modclose(sharefs_mod); 5610219089Spjd 5611219089Spjd tsd_destroy(&zfs_fsyncer_key); 5612219089Spjd ldi_ident_release(zfs_li); 5613219089Spjd zfs_li = NULL; 5614219089Spjd mutex_destroy(&zfs_share_lock); 5615219089Spjd 5616219089Spjd return (error); 5617219089Spjd} 5618219089Spjd 5619219089Spjdint 5620219089Spjd_info(struct modinfo *modinfop) 5621219089Spjd{ 5622219089Spjd return (mod_info(&modlinkage, modinfop)); 5623219089Spjd} 5624219089Spjd#endif /* sun */ 5625219089Spjd 5626168404Spjdstatic int 5627168404Spjdzfs_modevent(module_t mod, int type, void *unused __unused) 5628168404Spjd{ 5629196291Spjd int error = 0; 5630168404Spjd 5631168404Spjd switch (type) { 5632168404Spjd case MOD_LOAD: 5633190878Sthompsa zfs_root_token = root_mount_hold("ZFS"); 5634196291Spjd 5635185029Spjd mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 5636196291Spjd 5637196291Spjd spa_init(FREAD | FWRITE); 5638196291Spjd zfs_init(); 5639196291Spjd zvol_init(); 5640196291Spjd 5641196291Spjd tsd_create(&zfs_fsyncer_key, NULL); 5642196291Spjd tsd_create(&rrw_tsd_key, NULL); 5643196291Spjd 5644236884Smm printf("ZFS storage pool version: features support (" SPA_VERSION_STRING ")\n"); 5645196291Spjd root_mount_rel(zfs_root_token); 5646196291Spjd 5647196291Spjd zfsdev_init(); 5648168404Spjd break; 5649168404Spjd case MOD_UNLOAD: 5650168775Spjd if (spa_busy() || zfs_busy() || zvol_busy() || 5651168404Spjd zio_injection_enabled) { 5652168404Spjd error = EBUSY; 5653168404Spjd break; 5654168404Spjd } 5655196291Spjd 5656196291Spjd zfsdev_fini(); 5657168404Spjd zvol_fini(); 5658168404Spjd zfs_fini(); 5659168404Spjd spa_fini(); 5660196291Spjd 5661185029Spjd tsd_destroy(&zfs_fsyncer_key); 5662185029Spjd tsd_destroy(&rrw_tsd_key); 5663196291Spjd 5664185029Spjd mutex_destroy(&zfs_share_lock); 5665168404Spjd break; 5666196291Spjd default: 5667196291Spjd error = EOPNOTSUPP; 5668196291Spjd break; 5669168404Spjd } 5670168404Spjd return (error); 5671168404Spjd} 5672168404Spjd 5673168404Spjdstatic moduledata_t zfs_mod = { 5674168404Spjd "zfsctrl", 5675168404Spjd zfs_modevent, 5676241394Skevlo 0 5677168404Spjd}; 5678169929SpjdDECLARE_MODULE(zfsctrl, zfs_mod, SI_SUB_VFS, SI_ORDER_ANY); 5679246242SavgMODULE_VERSION(zfsctrl, 1); 5680179280SjbMODULE_DEPEND(zfsctrl, opensolaris, 1, 1, 1); 5681193128SkmacyMODULE_DEPEND(zfsctrl, krpc, 1, 1, 1); 5682232938SadrianMODULE_DEPEND(zfsctrl, acl_nfs4, 1, 1, 1); 5683