1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21ad135b5dSChristopher Siden 22fa9e4066Sahrens /* 233f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 240d8fa8f8SMartin Matuska * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved. 251df56adaSMartin Matuska * Portions Copyright 2011 Martin Matuska 265878fad7SDan McDonald * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. 276ccda740Sloli * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 2845b17475SAlex Wilson * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved. 292840dce1SChris Williamson * Copyright (c) 2011, 2017 by Delphix. All rights reserved. 30a6f561b4SSašo Kiselkov * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 31a7a845e4SSteven Hartland * Copyright (c) 2013 Steven Hartland. All rights reserved. 32c3d26abcSMatthew Ahrens * Copyright (c) 2014 Integros [integros.com] 33c8811bd3SToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com> 346ccda740Sloli * Copyright (c) 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved. 35a4b8c9aaSAndrew Stormont * Copyright 2017 RackTop Systems. 36eb633035STom Caputi * Copyright (c) 2017, Datto, Inc. All rights reserved. 374445fffbSMatthew Ahrens */ 384445fffbSMatthew Ahrens 394445fffbSMatthew Ahrens /* 404445fffbSMatthew Ahrens * ZFS ioctls. 414445fffbSMatthew Ahrens * 424445fffbSMatthew Ahrens * This file handles the ioctls to /dev/zfs, used for configuring ZFS storage 434445fffbSMatthew Ahrens * pools and filesystems, e.g. with /sbin/zfs and /sbin/zpool. 444445fffbSMatthew Ahrens * 454445fffbSMatthew Ahrens * There are two ways that we handle ioctls: the legacy way where almost 464445fffbSMatthew Ahrens * all of the logic is in the ioctl callback, and the new way where most 474445fffbSMatthew Ahrens * of the marshalling is handled in the common entry point, zfsdev_ioctl(). 484445fffbSMatthew Ahrens * 494445fffbSMatthew Ahrens * Non-legacy ioctls should be registered by calling 504445fffbSMatthew Ahrens * zfs_ioctl_register() from zfs_ioctl_init(). The ioctl is invoked 514445fffbSMatthew Ahrens * from userland by lzc_ioctl(). 524445fffbSMatthew Ahrens * 534445fffbSMatthew Ahrens * The registration arguments are as follows: 544445fffbSMatthew Ahrens * 554445fffbSMatthew Ahrens * const char *name 564445fffbSMatthew Ahrens * The name of the ioctl. This is used for history logging. If the 574445fffbSMatthew Ahrens * ioctl returns successfully (the callback returns 0), and allow_log 584445fffbSMatthew Ahrens * is true, then a history log entry will be recorded with the input & 594445fffbSMatthew Ahrens * output nvlists. The log entry can be printed with "zpool history -i". 604445fffbSMatthew Ahrens * 614445fffbSMatthew Ahrens * zfs_ioc_t ioc 624445fffbSMatthew Ahrens * The ioctl request number, which userland will pass to ioctl(2). 634445fffbSMatthew Ahrens * The ioctl numbers can change from release to release, because 644445fffbSMatthew Ahrens * the caller (libzfs) must be matched to the kernel. 654445fffbSMatthew Ahrens * 664445fffbSMatthew Ahrens * zfs_secpolicy_func_t *secpolicy 674445fffbSMatthew Ahrens * This function will be called before the zfs_ioc_func_t, to 684445fffbSMatthew Ahrens * determine if this operation is permitted. It should return EPERM 694445fffbSMatthew Ahrens * on failure, and 0 on success. Checks include determining if the 704445fffbSMatthew Ahrens * dataset is visible in this zone, and if the user has either all 714445fffbSMatthew Ahrens * zfs privileges in the zone (SYS_MOUNT), or has been granted permission 724445fffbSMatthew Ahrens * to do this operation on this dataset with "zfs allow". 734445fffbSMatthew Ahrens * 744445fffbSMatthew Ahrens * zfs_ioc_namecheck_t namecheck 754445fffbSMatthew Ahrens * This specifies what to expect in the zfs_cmd_t:zc_name -- a pool 764445fffbSMatthew Ahrens * name, a dataset name, or nothing. If the name is not well-formed, 774445fffbSMatthew Ahrens * the ioctl will fail and the callback will not be called. 784445fffbSMatthew Ahrens * Therefore, the callback can assume that the name is well-formed 794445fffbSMatthew Ahrens * (e.g. is null-terminated, doesn't have more than one '@' character, 804445fffbSMatthew Ahrens * doesn't have invalid characters). 814445fffbSMatthew Ahrens * 824445fffbSMatthew Ahrens * zfs_ioc_poolcheck_t pool_check 834445fffbSMatthew Ahrens * This specifies requirements on the pool state. If the pool does 844445fffbSMatthew Ahrens * not meet them (is suspended or is readonly), the ioctl will fail 854445fffbSMatthew Ahrens * and the callback will not be called. If any checks are specified 864445fffbSMatthew Ahrens * (i.e. it is not POOL_CHECK_NONE), namecheck must not be NO_NAME. 874445fffbSMatthew Ahrens * Multiple checks can be or-ed together (e.g. POOL_CHECK_SUSPENDED | 884445fffbSMatthew Ahrens * POOL_CHECK_READONLY). 894445fffbSMatthew Ahrens * 904445fffbSMatthew Ahrens * boolean_t smush_outnvlist 914445fffbSMatthew Ahrens * If smush_outnvlist is true, then the output is presumed to be a 924445fffbSMatthew Ahrens * list of errors, and it will be "smushed" down to fit into the 934445fffbSMatthew Ahrens * caller's buffer, by removing some entries and replacing them with a 944445fffbSMatthew Ahrens * single "N_MORE_ERRORS" entry indicating how many were removed. See 954445fffbSMatthew Ahrens * nvlist_smush() for details. If smush_outnvlist is false, and the 964445fffbSMatthew Ahrens * outnvlist does not fit into the userland-provided buffer, then the 974445fffbSMatthew Ahrens * ioctl will fail with ENOMEM. 984445fffbSMatthew Ahrens * 994445fffbSMatthew Ahrens * zfs_ioc_func_t *func 1004445fffbSMatthew Ahrens * The callback function that will perform the operation. 1014445fffbSMatthew Ahrens * 1024445fffbSMatthew Ahrens * The callback should return 0 on success, or an error number on 1034445fffbSMatthew Ahrens * failure. If the function fails, the userland ioctl will return -1, 1044445fffbSMatthew Ahrens * and errno will be set to the callback's return value. The callback 1054445fffbSMatthew Ahrens * will be called with the following arguments: 1064445fffbSMatthew Ahrens * 1074445fffbSMatthew Ahrens * const char *name 1084445fffbSMatthew Ahrens * The name of the pool or dataset to operate on, from 1094445fffbSMatthew Ahrens * zfs_cmd_t:zc_name. The 'namecheck' argument specifies the 1104445fffbSMatthew Ahrens * expected type (pool, dataset, or none). 1114445fffbSMatthew Ahrens * 1124445fffbSMatthew Ahrens * nvlist_t *innvl 1134445fffbSMatthew Ahrens * The input nvlist, deserialized from zfs_cmd_t:zc_nvlist_src. Or 1144445fffbSMatthew Ahrens * NULL if no input nvlist was provided. Changes to this nvlist are 1154445fffbSMatthew Ahrens * ignored. If the input nvlist could not be deserialized, the 1164445fffbSMatthew Ahrens * ioctl will fail and the callback will not be called. 1174445fffbSMatthew Ahrens * 1184445fffbSMatthew Ahrens * nvlist_t *outnvl 1194445fffbSMatthew Ahrens * The output nvlist, initially empty. The callback can fill it in, 1204445fffbSMatthew Ahrens * and it will be returned to userland by serializing it into 1214445fffbSMatthew Ahrens * zfs_cmd_t:zc_nvlist_dst. If it is non-empty, and serialization 1224445fffbSMatthew Ahrens * fails (e.g. because the caller didn't supply a large enough 1234445fffbSMatthew Ahrens * buffer), then the overall ioctl will fail. See the 1244445fffbSMatthew Ahrens * 'smush_nvlist' argument above for additional behaviors. 1254445fffbSMatthew Ahrens * 1264445fffbSMatthew Ahrens * There are two typical uses of the output nvlist: 1274445fffbSMatthew Ahrens * - To return state, e.g. property values. In this case, 1284445fffbSMatthew Ahrens * smush_outnvlist should be false. If the buffer was not large 1294445fffbSMatthew Ahrens * enough, the caller will reallocate a larger buffer and try 1304445fffbSMatthew Ahrens * the ioctl again. 1314445fffbSMatthew Ahrens * 1324445fffbSMatthew Ahrens * - To return multiple errors from an ioctl which makes on-disk 1334445fffbSMatthew Ahrens * changes. In this case, smush_outnvlist should be true. 1344445fffbSMatthew Ahrens * Ioctls which make on-disk modifications should generally not 1354445fffbSMatthew Ahrens * use the outnvl if they succeed, because the caller can not 1364445fffbSMatthew Ahrens * distinguish between the operation failing, and 1374445fffbSMatthew Ahrens * deserialization failing. 138e9103aaeSGarrett D'Amore */ 139fa9e4066Sahrens 140fa9e4066Sahrens #include <sys/types.h> 141fa9e4066Sahrens #include <sys/param.h> 142fa9e4066Sahrens #include <sys/errno.h> 143fa9e4066Sahrens #include <sys/uio.h> 144fa9e4066Sahrens #include <sys/buf.h> 145fa9e4066Sahrens #include <sys/modctl.h> 146fa9e4066Sahrens #include <sys/open.h> 147fa9e4066Sahrens #include <sys/file.h> 148fa9e4066Sahrens #include <sys/kmem.h> 149fa9e4066Sahrens #include <sys/conf.h> 150fa9e4066Sahrens #include <sys/cmn_err.h> 151fa9e4066Sahrens #include <sys/stat.h> 152fa9e4066Sahrens #include <sys/zfs_ioctl.h> 1534201a95eSRic Aleshire #include <sys/zfs_vfsops.h> 154da6c28aaSamw #include <sys/zfs_znode.h> 155fa9e4066Sahrens #include <sys/zap.h> 156fa9e4066Sahrens #include <sys/spa.h> 157b1b8ab34Slling #include <sys/spa_impl.h> 158fa9e4066Sahrens #include <sys/vdev.h> 1594201a95eSRic Aleshire #include <sys/priv_impl.h> 160fa9e4066Sahrens #include <sys/dmu.h> 161fa9e4066Sahrens #include <sys/dsl_dir.h> 162fa9e4066Sahrens #include <sys/dsl_dataset.h> 163fa9e4066Sahrens #include <sys/dsl_prop.h> 164ecd6cf80Smarks #include <sys/dsl_deleg.h> 165ecd6cf80Smarks #include <sys/dmu_objset.h> 1664e3c9f44SBill Pijewski #include <sys/dmu_impl.h> 1673b2aab18SMatthew Ahrens #include <sys/dmu_tx.h> 168fa9e4066Sahrens #include <sys/ddi.h> 169fa9e4066Sahrens #include <sys/sunddi.h> 170fa9e4066Sahrens #include <sys/sunldi.h> 171fa9e4066Sahrens #include <sys/policy.h> 172fa9e4066Sahrens #include <sys/zone.h> 173fa9e4066Sahrens #include <sys/nvpair.h> 174fa9e4066Sahrens #include <sys/pathname.h> 175fa9e4066Sahrens #include <sys/mount.h> 176fa9e4066Sahrens #include <sys/sdt.h> 177fa9e4066Sahrens #include <sys/fs/zfs.h> 178fa9e4066Sahrens #include <sys/zfs_ctldir.h> 179da6c28aaSamw #include <sys/zfs_dir.h> 180c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 181a2eea2e1Sahrens #include <sys/zvol.h> 1823f9d6ad7SLin Ling #include <sys/dsl_scan.h> 183ecd6cf80Smarks #include <sharefs/share.h> 184f18faf3fSek #include <sys/dmu_objset.h> 1850fa1b3ccSPaul Dagnelie #include <sys/dmu_recv.h> 1863b2aab18SMatthew Ahrens #include <sys/dmu_send.h> 1873b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 18878f17100SMatthew Ahrens #include <sys/dsl_bookmark.h> 1893b2aab18SMatthew Ahrens #include <sys/dsl_userhold.h> 190a6f561b4SSašo Kiselkov #include <sys/zfeature.h> 191dfc11533SChris Williamson #include <sys/zcp.h> 19245818ee1SMatthew Ahrens #include <sys/zio_checksum.h> 1935cabbc6bSPrashanth Sreenivasa #include <sys/vdev_removal.h> 194094e47e9SGeorge Wilson #include <sys/vdev_impl.h> 195094e47e9SGeorge Wilson #include <sys/vdev_initialize.h> 196*084fd14fSBrian Behlendorf #include <sys/vdev_trim.h> 197eb633035STom Caputi #include <sys/dsl_crypt.h> 198fa9e4066Sahrens 199fa9e4066Sahrens #include "zfs_namecheck.h" 200e9dbad6fSeschrock #include "zfs_prop.h" 201ecd6cf80Smarks #include "zfs_deleg.h" 2020a586ceaSMark Shellenbaum #include "zfs_comutil.h" 203fa9e4066Sahrens 204dfc11533SChris Williamson #include "lua.h" 205dfc11533SChris Williamson #include "lauxlib.h" 206dfc11533SChris Williamson 207fa9e4066Sahrens extern struct modlfs zfs_modlfs; 208fa9e4066Sahrens 209fa9e4066Sahrens extern void zfs_init(void); 210fa9e4066Sahrens extern void zfs_fini(void); 211fa9e4066Sahrens 212fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 213fa9e4066Sahrens dev_info_t *zfs_dip; 214fa9e4066Sahrens 2154445fffbSMatthew Ahrens uint_t zfs_fsyncer_key; 2164445fffbSMatthew Ahrens extern uint_t rrw_tsd_key; 2174445fffbSMatthew Ahrens static uint_t zfs_allow_log_key; 2184445fffbSMatthew Ahrens 2194445fffbSMatthew Ahrens typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *); 2204445fffbSMatthew Ahrens typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *); 2214445fffbSMatthew Ahrens typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *); 222fa9e4066Sahrens 22354d692b7SGeorge Wilson typedef enum { 22454d692b7SGeorge Wilson NO_NAME, 22554d692b7SGeorge Wilson POOL_NAME, 22654d692b7SGeorge Wilson DATASET_NAME 22754d692b7SGeorge Wilson } zfs_ioc_namecheck_t; 22854d692b7SGeorge Wilson 229f9af39baSGeorge Wilson typedef enum { 230f9af39baSGeorge Wilson POOL_CHECK_NONE = 1 << 0, 231f9af39baSGeorge Wilson POOL_CHECK_SUSPENDED = 1 << 1, 2324445fffbSMatthew Ahrens POOL_CHECK_READONLY = 1 << 2, 233f9af39baSGeorge Wilson } zfs_ioc_poolcheck_t; 234f9af39baSGeorge Wilson 235fa9e4066Sahrens typedef struct zfs_ioc_vec { 2364445fffbSMatthew Ahrens zfs_ioc_legacy_func_t *zvec_legacy_func; 237fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 238fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 23954d692b7SGeorge Wilson zfs_ioc_namecheck_t zvec_namecheck; 2404445fffbSMatthew Ahrens boolean_t zvec_allow_log; 241f9af39baSGeorge Wilson zfs_ioc_poolcheck_t zvec_pool_check; 2424445fffbSMatthew Ahrens boolean_t zvec_smush_outnvlist; 2434445fffbSMatthew Ahrens const char *zvec_name; 244fa9e4066Sahrens } zfs_ioc_vec_t; 245fa9e4066Sahrens 24614843421SMatthew Ahrens /* This array is indexed by zfs_userquota_prop_t */ 24714843421SMatthew Ahrens static const char *userquota_perms[] = { 24814843421SMatthew Ahrens ZFS_DELEG_PERM_USERUSED, 24914843421SMatthew Ahrens ZFS_DELEG_PERM_USERQUOTA, 25014843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPUSED, 25114843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPQUOTA, 252f67950b2SNasf-Fan ZFS_DELEG_PERM_USEROBJUSED, 253f67950b2SNasf-Fan ZFS_DELEG_PERM_USEROBJQUOTA, 254f67950b2SNasf-Fan ZFS_DELEG_PERM_GROUPOBJUSED, 255f67950b2SNasf-Fan ZFS_DELEG_PERM_GROUPOBJQUOTA, 256f67950b2SNasf-Fan ZFS_DELEG_PERM_PROJECTUSED, 257f67950b2SNasf-Fan ZFS_DELEG_PERM_PROJECTQUOTA, 258f67950b2SNasf-Fan ZFS_DELEG_PERM_PROJECTOBJUSED, 259f67950b2SNasf-Fan ZFS_DELEG_PERM_PROJECTOBJQUOTA, 26014843421SMatthew Ahrens }; 26114843421SMatthew Ahrens 26214843421SMatthew Ahrens static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 263f67950b2SNasf-Fan static int zfs_ioc_id_quota_upgrade(zfs_cmd_t *zc); 26492241e0bSTom Erickson static int zfs_check_settable(const char *name, nvpair_t *property, 26592241e0bSTom Erickson cred_t *cr); 26692241e0bSTom Erickson static int zfs_check_clearable(char *dataset, nvlist_t *props, 26792241e0bSTom Erickson nvlist_t **errors); 2680a48a24eStimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 2690a48a24eStimh boolean_t *); 2704445fffbSMatthew Ahrens int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *); 2714445fffbSMatthew Ahrens static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp); 2720a48a24eStimh 2732acef22dSMatthew Ahrens static int zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature); 274a6f561b4SSašo Kiselkov 275fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 276fa9e4066Sahrens void 277fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 278fa9e4066Sahrens { 279fa9e4066Sahrens const char *newfile; 2803f9d6ad7SLin Ling char buf[512]; 281fa9e4066Sahrens va_list adx; 282fa9e4066Sahrens 283fa9e4066Sahrens /* 284fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 285fa9e4066Sahrens */ 286fa9e4066Sahrens newfile = strrchr(file, '/'); 287fa9e4066Sahrens if (newfile != NULL) { 288fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 289fa9e4066Sahrens } else { 290fa9e4066Sahrens newfile = file; 291fa9e4066Sahrens } 292fa9e4066Sahrens 293fa9e4066Sahrens va_start(adx, fmt); 294fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 295fa9e4066Sahrens va_end(adx); 296fa9e4066Sahrens 297fa9e4066Sahrens /* 298fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 299fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 300fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 301fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 302fa9e4066Sahrens * arg0 = file name 303fa9e4066Sahrens * arg1 = function name 304fa9e4066Sahrens * arg2 = line number 305fa9e4066Sahrens * arg3 = message 306fa9e4066Sahrens */ 307fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 308fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 309fa9e4066Sahrens } 310fa9e4066Sahrens 311ecd6cf80Smarks static void 312228975ccSek history_str_free(char *buf) 313228975ccSek { 314228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 315228975ccSek } 316228975ccSek 317228975ccSek static char * 318228975ccSek history_str_get(zfs_cmd_t *zc) 319ecd6cf80Smarks { 32040feaa91Sahrens char *buf; 321ecd6cf80Smarks 322dd328bf6SToomas Soome if (zc->zc_history == 0) 323228975ccSek return (NULL); 324e7437265Sahrens 325ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 326ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 327ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 328228975ccSek history_str_free(buf); 329228975ccSek return (NULL); 330ecd6cf80Smarks } 331ecd6cf80Smarks 332ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 333ecd6cf80Smarks 334228975ccSek return (buf); 335228975ccSek } 336ecd6cf80Smarks 33715e6edf1Sgw /* 33815e6edf1Sgw * Check to see if the named dataset is currently defined as bootable 33915e6edf1Sgw */ 34015e6edf1Sgw static boolean_t 34115e6edf1Sgw zfs_is_bootfs(const char *name) 34215e6edf1Sgw { 343503ad85cSMatthew Ahrens objset_t *os; 34415e6edf1Sgw 345503ad85cSMatthew Ahrens if (dmu_objset_hold(name, FTAG, &os) == 0) { 346503ad85cSMatthew Ahrens boolean_t ret; 347b24ab676SJeff Bonwick ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os))); 348503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 349503ad85cSMatthew Ahrens return (ret); 35015e6edf1Sgw } 351503ad85cSMatthew Ahrens return (B_FALSE); 35215e6edf1Sgw } 35315e6edf1Sgw 354c2a93d44Stimh /* 355f7170741SWill Andrews * Return non-zero if the spa version is less than requested version. 356c2a93d44Stimh */ 357da6c28aaSamw static int 3580a48a24eStimh zfs_earlier_version(const char *name, int version) 359da6c28aaSamw { 360da6c28aaSamw spa_t *spa; 361da6c28aaSamw 362da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 363da6c28aaSamw if (spa_version(spa) < version) { 364da6c28aaSamw spa_close(spa, FTAG); 365da6c28aaSamw return (1); 366da6c28aaSamw } 367da6c28aaSamw spa_close(spa, FTAG); 368da6c28aaSamw } 369da6c28aaSamw return (0); 370da6c28aaSamw } 371da6c28aaSamw 3729e6eda55Smarks /* 373745cd3c5Smaybee * Return TRUE if the ZPL version is less than requested version. 3749e6eda55Smarks */ 375745cd3c5Smaybee static boolean_t 376745cd3c5Smaybee zpl_earlier_version(const char *name, int version) 3779e6eda55Smarks { 3789e6eda55Smarks objset_t *os; 379745cd3c5Smaybee boolean_t rc = B_TRUE; 3809e6eda55Smarks 381503ad85cSMatthew Ahrens if (dmu_objset_hold(name, FTAG, &os) == 0) { 382745cd3c5Smaybee uint64_t zplversion; 3839e6eda55Smarks 384503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 385503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 386503ad85cSMatthew Ahrens return (B_TRUE); 387503ad85cSMatthew Ahrens } 388503ad85cSMatthew Ahrens /* XXX reading from non-owned objset */ 389745cd3c5Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 390745cd3c5Smaybee rc = zplversion < version; 391503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 3929e6eda55Smarks } 3939e6eda55Smarks return (rc); 3949e6eda55Smarks } 3959e6eda55Smarks 396228975ccSek static void 397228975ccSek zfs_log_history(zfs_cmd_t *zc) 398228975ccSek { 399228975ccSek spa_t *spa; 400228975ccSek char *buf; 401ecd6cf80Smarks 402228975ccSek if ((buf = history_str_get(zc)) == NULL) 403228975ccSek return; 404228975ccSek 405228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 406228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 4074445fffbSMatthew Ahrens (void) spa_history_log(spa, buf); 408228975ccSek spa_close(spa, FTAG); 409228975ccSek } 410228975ccSek history_str_free(buf); 411ecd6cf80Smarks } 412ecd6cf80Smarks 413fa9e4066Sahrens /* 414fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 415fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 416fa9e4066Sahrens */ 417fa9e4066Sahrens /* ARGSUSED */ 418fa9e4066Sahrens static int 4194445fffbSMatthew Ahrens zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 420fa9e4066Sahrens { 421fa9e4066Sahrens return (0); 422fa9e4066Sahrens } 423fa9e4066Sahrens 424fa9e4066Sahrens /* 425fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 426fa9e4066Sahrens * no privileges, but must be visible in the local zone. 427fa9e4066Sahrens */ 428fa9e4066Sahrens /* ARGSUSED */ 429fa9e4066Sahrens static int 4304445fffbSMatthew Ahrens zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 431fa9e4066Sahrens { 432fa9e4066Sahrens if (INGLOBALZONE(curproc) || 433ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 434fa9e4066Sahrens return (0); 435fa9e4066Sahrens 436be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 437fa9e4066Sahrens } 438fa9e4066Sahrens 439fa9e4066Sahrens static int 440a7f53a56SChris Kirby zfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr) 441fa9e4066Sahrens { 442fa9e4066Sahrens int writable = 1; 443fa9e4066Sahrens 444fa9e4066Sahrens /* 445fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 446fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 447fa9e4066Sahrens */ 448fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 449fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 450be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 451fa9e4066Sahrens 452fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 453fa9e4066Sahrens /* 454fa9e4066Sahrens * If the fs is zoned, only root can access it from the 455fa9e4066Sahrens * global zone. 456fa9e4066Sahrens */ 457fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 458be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 459fa9e4066Sahrens } else { 460fa9e4066Sahrens /* 461fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 462fa9e4066Sahrens */ 463fa9e4066Sahrens if (!zoned) 464be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 465fa9e4066Sahrens 466fa9e4066Sahrens /* must be writable by this zone */ 467fa9e4066Sahrens if (!writable) 468be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 469fa9e4066Sahrens } 470fa9e4066Sahrens return (0); 471fa9e4066Sahrens } 472fa9e4066Sahrens 473a7f53a56SChris Kirby static int 474a7f53a56SChris Kirby zfs_dozonecheck(const char *dataset, cred_t *cr) 475a7f53a56SChris Kirby { 476a7f53a56SChris Kirby uint64_t zoned; 477a7f53a56SChris Kirby 478a7f53a56SChris Kirby if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 479be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 480a7f53a56SChris Kirby 481a7f53a56SChris Kirby return (zfs_dozonecheck_impl(dataset, zoned, cr)); 482a7f53a56SChris Kirby } 483a7f53a56SChris Kirby 484a7f53a56SChris Kirby static int 485a7f53a56SChris Kirby zfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr) 486a7f53a56SChris Kirby { 487a7f53a56SChris Kirby uint64_t zoned; 488a7f53a56SChris Kirby 4893b2aab18SMatthew Ahrens if (dsl_prop_get_int_ds(ds, "zoned", &zoned)) 490be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 491a7f53a56SChris Kirby 492a7f53a56SChris Kirby return (zfs_dozonecheck_impl(dataset, zoned, cr)); 493a7f53a56SChris Kirby } 494a7f53a56SChris Kirby 4954445fffbSMatthew Ahrens static int 4963b2aab18SMatthew Ahrens zfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds, 4973b2aab18SMatthew Ahrens const char *perm, cred_t *cr) 498fa9e4066Sahrens { 499fa9e4066Sahrens int error; 500fa9e4066Sahrens 50119b94df9SMatthew Ahrens error = zfs_dozonecheck_ds(name, ds, cr); 502ecd6cf80Smarks if (error == 0) { 503ecd6cf80Smarks error = secpolicy_zfs(cr); 5043b2aab18SMatthew Ahrens if (error != 0) 5054445fffbSMatthew Ahrens error = dsl_deleg_access_impl(ds, perm, cr); 506ecd6cf80Smarks } 507ecd6cf80Smarks return (error); 508ecd6cf80Smarks } 509ecd6cf80Smarks 5104445fffbSMatthew Ahrens static int 5113b2aab18SMatthew Ahrens zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 512a7f53a56SChris Kirby { 513a7f53a56SChris Kirby int error; 5143b2aab18SMatthew Ahrens dsl_dataset_t *ds; 5153b2aab18SMatthew Ahrens dsl_pool_t *dp; 516a7f53a56SChris Kirby 51725f7d993SMatthew Ahrens /* 51825f7d993SMatthew Ahrens * First do a quick check for root in the global zone, which 51925f7d993SMatthew Ahrens * is allowed to do all write_perms. This ensures that zfs_ioc_* 52025f7d993SMatthew Ahrens * will get to handle nonexistent datasets. 52125f7d993SMatthew Ahrens */ 52225f7d993SMatthew Ahrens if (INGLOBALZONE(curproc) && secpolicy_zfs(cr) == 0) 52325f7d993SMatthew Ahrens return (0); 52425f7d993SMatthew Ahrens 5253b2aab18SMatthew Ahrens error = dsl_pool_hold(name, FTAG, &dp); 5263b2aab18SMatthew Ahrens if (error != 0) 5273b2aab18SMatthew Ahrens return (error); 5283b2aab18SMatthew Ahrens 5293b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, name, FTAG, &ds); 5303b2aab18SMatthew Ahrens if (error != 0) { 5313b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 5323b2aab18SMatthew Ahrens return (error); 533a7f53a56SChris Kirby } 5343b2aab18SMatthew Ahrens 5353b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms_ds(name, ds, perm, cr); 5363b2aab18SMatthew Ahrens 5373b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 5383b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 539a7f53a56SChris Kirby return (error); 540a7f53a56SChris Kirby } 541a7f53a56SChris Kirby 5424201a95eSRic Aleshire /* 5434201a95eSRic Aleshire * Policy for setting the security label property. 5444201a95eSRic Aleshire * 5454201a95eSRic Aleshire * Returns 0 for success, non-zero for access and other errors. 5464201a95eSRic Aleshire */ 5474201a95eSRic Aleshire static int 54892241e0bSTom Erickson zfs_set_slabel_policy(const char *name, char *strval, cred_t *cr) 5494201a95eSRic Aleshire { 5504201a95eSRic Aleshire char ds_hexsl[MAXNAMELEN]; 5514201a95eSRic Aleshire bslabel_t ds_sl, new_sl; 5524201a95eSRic Aleshire boolean_t new_default = FALSE; 5534201a95eSRic Aleshire uint64_t zoned; 5544201a95eSRic Aleshire int needed_priv = -1; 5554201a95eSRic Aleshire int error; 5564201a95eSRic Aleshire 5574201a95eSRic Aleshire /* First get the existing dataset label. */ 5584201a95eSRic Aleshire error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 5594201a95eSRic Aleshire 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 5603b2aab18SMatthew Ahrens if (error != 0) 561be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5624201a95eSRic Aleshire 5634201a95eSRic Aleshire if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 5644201a95eSRic Aleshire new_default = TRUE; 5654201a95eSRic Aleshire 5664201a95eSRic Aleshire /* The label must be translatable */ 5674201a95eSRic Aleshire if (!new_default && (hexstr_to_label(strval, &new_sl) != 0)) 568be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5694201a95eSRic Aleshire 5704201a95eSRic Aleshire /* 5714201a95eSRic Aleshire * In a non-global zone, disallow attempts to set a label that 5724201a95eSRic Aleshire * doesn't match that of the zone; otherwise no other checks 5734201a95eSRic Aleshire * are needed. 5744201a95eSRic Aleshire */ 5754201a95eSRic Aleshire if (!INGLOBALZONE(curproc)) { 5764201a95eSRic Aleshire if (new_default || !blequal(&new_sl, CR_SL(CRED()))) 577be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5784201a95eSRic Aleshire return (0); 5794201a95eSRic Aleshire } 5804201a95eSRic Aleshire 5814201a95eSRic Aleshire /* 5824201a95eSRic Aleshire * For global-zone datasets (i.e., those whose zoned property is 5834201a95eSRic Aleshire * "off", verify that the specified new label is valid for the 5844201a95eSRic Aleshire * global zone. 5854201a95eSRic Aleshire */ 5864201a95eSRic Aleshire if (dsl_prop_get_integer(name, 5874201a95eSRic Aleshire zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) 588be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5894201a95eSRic Aleshire if (!zoned) { 5904201a95eSRic Aleshire if (zfs_check_global_label(name, strval) != 0) 591be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5924201a95eSRic Aleshire } 5934201a95eSRic Aleshire 5944201a95eSRic Aleshire /* 5954201a95eSRic Aleshire * If the existing dataset label is nondefault, check if the 5964201a95eSRic Aleshire * dataset is mounted (label cannot be changed while mounted). 5974201a95eSRic Aleshire * Get the zfsvfs; if there isn't one, then the dataset isn't 5984201a95eSRic Aleshire * mounted (or isn't a dataset, doesn't exist, ...). 5994201a95eSRic Aleshire */ 6004201a95eSRic Aleshire if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) { 60192241e0bSTom Erickson objset_t *os; 60292241e0bSTom Erickson static char *setsl_tag = "setsl_tag"; 60392241e0bSTom Erickson 6044201a95eSRic Aleshire /* 6054201a95eSRic Aleshire * Try to own the dataset; abort if there is any error, 6064201a95eSRic Aleshire * (e.g., already mounted, in use, or other error). 6074201a95eSRic Aleshire */ 608eb633035STom Caputi error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE, B_TRUE, 60992241e0bSTom Erickson setsl_tag, &os); 6103b2aab18SMatthew Ahrens if (error != 0) 611be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 6124201a95eSRic Aleshire 613eb633035STom Caputi dmu_objset_disown(os, B_TRUE, setsl_tag); 61492241e0bSTom Erickson 6154201a95eSRic Aleshire if (new_default) { 6164201a95eSRic Aleshire needed_priv = PRIV_FILE_DOWNGRADE_SL; 6174201a95eSRic Aleshire goto out_check; 6184201a95eSRic Aleshire } 6194201a95eSRic Aleshire 6204201a95eSRic Aleshire if (hexstr_to_label(strval, &new_sl) != 0) 621be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 6224201a95eSRic Aleshire 6234201a95eSRic Aleshire if (blstrictdom(&ds_sl, &new_sl)) 6244201a95eSRic Aleshire needed_priv = PRIV_FILE_DOWNGRADE_SL; 6254201a95eSRic Aleshire else if (blstrictdom(&new_sl, &ds_sl)) 6264201a95eSRic Aleshire needed_priv = PRIV_FILE_UPGRADE_SL; 6274201a95eSRic Aleshire } else { 6284201a95eSRic Aleshire /* dataset currently has a default label */ 6294201a95eSRic Aleshire if (!new_default) 6304201a95eSRic Aleshire needed_priv = PRIV_FILE_UPGRADE_SL; 6314201a95eSRic Aleshire } 6324201a95eSRic Aleshire 6334201a95eSRic Aleshire out_check: 6344201a95eSRic Aleshire if (needed_priv != -1) 6354201a95eSRic Aleshire return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL)); 6364201a95eSRic Aleshire return (0); 6374201a95eSRic Aleshire } 6384201a95eSRic Aleshire 639ecd6cf80Smarks static int 64092241e0bSTom Erickson zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval, 64192241e0bSTom Erickson cred_t *cr) 642ecd6cf80Smarks { 64392241e0bSTom Erickson char *strval; 64492241e0bSTom Erickson 645ecd6cf80Smarks /* 646ecd6cf80Smarks * Check permissions for special properties. 647ecd6cf80Smarks */ 648ecd6cf80Smarks switch (prop) { 649ecd6cf80Smarks case ZFS_PROP_ZONED: 650ecd6cf80Smarks /* 651ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 652ecd6cf80Smarks */ 653ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 654be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 655ecd6cf80Smarks break; 656ecd6cf80Smarks 657ecd6cf80Smarks case ZFS_PROP_QUOTA: 658a2afb611SJerry Jelinek case ZFS_PROP_FILESYSTEM_LIMIT: 659a2afb611SJerry Jelinek case ZFS_PROP_SNAPSHOT_LIMIT: 660ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 661ecd6cf80Smarks uint64_t zoned; 6629adfa60dSMatthew Ahrens char setpoint[ZFS_MAX_DATASET_NAME_LEN]; 663ecd6cf80Smarks /* 664ecd6cf80Smarks * Unprivileged users are allowed to modify the 665a2afb611SJerry Jelinek * limit on things *under* (ie. contained by) 666ecd6cf80Smarks * the thing they own. 667ecd6cf80Smarks */ 66892241e0bSTom Erickson if (dsl_prop_get_integer(dsname, "zoned", &zoned, 669ecd6cf80Smarks setpoint)) 670be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 67192241e0bSTom Erickson if (!zoned || strlen(dsname) <= strlen(setpoint)) 672be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 673ecd6cf80Smarks } 674db870a07Sahrens break; 6754201a95eSRic Aleshire 6764201a95eSRic Aleshire case ZFS_PROP_MLSLABEL: 6774201a95eSRic Aleshire if (!is_system_labeled()) 678be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 67992241e0bSTom Erickson 68092241e0bSTom Erickson if (nvpair_value_string(propval, &strval) == 0) { 68192241e0bSTom Erickson int err; 68292241e0bSTom Erickson 68392241e0bSTom Erickson err = zfs_set_slabel_policy(dsname, strval, CRED()); 68492241e0bSTom Erickson if (err != 0) 68592241e0bSTom Erickson return (err); 68692241e0bSTom Erickson } 6874201a95eSRic Aleshire break; 688ecd6cf80Smarks } 689ecd6cf80Smarks 69092241e0bSTom Erickson return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr)); 691ecd6cf80Smarks } 692ecd6cf80Smarks 6934445fffbSMatthew Ahrens /* ARGSUSED */ 6944445fffbSMatthew Ahrens static int 6954445fffbSMatthew Ahrens zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 696ecd6cf80Smarks { 697ecd6cf80Smarks int error; 698ecd6cf80Smarks 699ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 7003b2aab18SMatthew Ahrens if (error != 0) 701fa9e4066Sahrens return (error); 702fa9e4066Sahrens 703ecd6cf80Smarks /* 704ecd6cf80Smarks * permission to set permissions will be evaluated later in 705ecd6cf80Smarks * dsl_deleg_can_allow() 706ecd6cf80Smarks */ 707ecd6cf80Smarks return (0); 708ecd6cf80Smarks } 709ecd6cf80Smarks 7104445fffbSMatthew Ahrens /* ARGSUSED */ 7114445fffbSMatthew Ahrens static int 7124445fffbSMatthew Ahrens zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 713ecd6cf80Smarks { 714681d9761SEric Taylor return (zfs_secpolicy_write_perms(zc->zc_name, 715681d9761SEric Taylor ZFS_DELEG_PERM_ROLLBACK, cr)); 716ecd6cf80Smarks } 717ecd6cf80Smarks 7184445fffbSMatthew Ahrens /* ARGSUSED */ 7194445fffbSMatthew Ahrens static int 7204445fffbSMatthew Ahrens zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 721ecd6cf80Smarks { 722a7f53a56SChris Kirby dsl_pool_t *dp; 723a7f53a56SChris Kirby dsl_dataset_t *ds; 724a7f53a56SChris Kirby char *cp; 725a7f53a56SChris Kirby int error; 726a7f53a56SChris Kirby 727a7f53a56SChris Kirby /* 728a7f53a56SChris Kirby * Generate the current snapshot name from the given objsetid, then 729a7f53a56SChris Kirby * use that name for the secpolicy/zone checks. 730a7f53a56SChris Kirby */ 731a7f53a56SChris Kirby cp = strchr(zc->zc_name, '@'); 732a7f53a56SChris Kirby if (cp == NULL) 733be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 7343b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 7353b2aab18SMatthew Ahrens if (error != 0) 736a7f53a56SChris Kirby return (error); 737a7f53a56SChris Kirby 738a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 7393b2aab18SMatthew Ahrens if (error != 0) { 7403b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 741a7f53a56SChris Kirby return (error); 7423b2aab18SMatthew Ahrens } 743a7f53a56SChris Kirby 744a7f53a56SChris Kirby dsl_dataset_name(ds, zc->zc_name); 745a7f53a56SChris Kirby 746a7f53a56SChris Kirby error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds, 747a7f53a56SChris Kirby ZFS_DELEG_PERM_SEND, cr); 748a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 7493b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 750a7f53a56SChris Kirby 751a7f53a56SChris Kirby return (error); 752ecd6cf80Smarks } 753ecd6cf80Smarks 7544445fffbSMatthew Ahrens /* ARGSUSED */ 755743a77edSAlan Wright static int 7564445fffbSMatthew Ahrens zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 7574445fffbSMatthew Ahrens { 7584445fffbSMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 7594445fffbSMatthew Ahrens ZFS_DELEG_PERM_SEND, cr)); 7604445fffbSMatthew Ahrens } 7614445fffbSMatthew Ahrens 7624445fffbSMatthew Ahrens /* ARGSUSED */ 7634445fffbSMatthew Ahrens static int 7644445fffbSMatthew Ahrens zfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 765743a77edSAlan Wright { 766743a77edSAlan Wright vnode_t *vp; 767743a77edSAlan Wright int error; 768743a77edSAlan Wright 769743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 770743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 771743a77edSAlan Wright return (error); 772743a77edSAlan Wright 773743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 774743a77edSAlan Wright 775743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 776743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 777743a77edSAlan Wright zc->zc_name) != 0)) { 778743a77edSAlan Wright VN_RELE(vp); 779be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 780743a77edSAlan Wright } 781743a77edSAlan Wright 782743a77edSAlan Wright VN_RELE(vp); 783743a77edSAlan Wright return (dsl_deleg_access(zc->zc_name, 784743a77edSAlan Wright ZFS_DELEG_PERM_SHARE, cr)); 785743a77edSAlan Wright } 786743a77edSAlan Wright 787ecd6cf80Smarks int 7884445fffbSMatthew Ahrens zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 789ecd6cf80Smarks { 790ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 791be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 792ecd6cf80Smarks 7933cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 794ecd6cf80Smarks return (0); 795ecd6cf80Smarks } else { 7964445fffbSMatthew Ahrens return (zfs_secpolicy_deleg_share(zc, innvl, cr)); 797743a77edSAlan Wright } 798743a77edSAlan Wright } 799ecd6cf80Smarks 800743a77edSAlan Wright int 8014445fffbSMatthew Ahrens zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 802743a77edSAlan Wright { 803743a77edSAlan Wright if (!INGLOBALZONE(curproc)) 804be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 805ecd6cf80Smarks 806743a77edSAlan Wright if (secpolicy_smb(cr) == 0) { 807743a77edSAlan Wright return (0); 808743a77edSAlan Wright } else { 8094445fffbSMatthew Ahrens return (zfs_secpolicy_deleg_share(zc, innvl, cr)); 810ecd6cf80Smarks } 811fa9e4066Sahrens } 812fa9e4066Sahrens 813fa9e4066Sahrens static int 814ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 815fa9e4066Sahrens { 816fa9e4066Sahrens char *cp; 817fa9e4066Sahrens 818fa9e4066Sahrens /* 819fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 820fa9e4066Sahrens */ 821ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 822ecd6cf80Smarks cp = strrchr(parent, '@'); 823fa9e4066Sahrens if (cp != NULL) { 824fa9e4066Sahrens cp[0] = '\0'; 825fa9e4066Sahrens } else { 826ecd6cf80Smarks cp = strrchr(parent, '/'); 827fa9e4066Sahrens if (cp == NULL) 828be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 829fa9e4066Sahrens cp[0] = '\0'; 830ecd6cf80Smarks } 831ecd6cf80Smarks 832ecd6cf80Smarks return (0); 833ecd6cf80Smarks } 834ecd6cf80Smarks 835ecd6cf80Smarks int 836ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 837ecd6cf80Smarks { 838ecd6cf80Smarks int error; 839ecd6cf80Smarks 840ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 841ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 842ecd6cf80Smarks return (error); 843ecd6cf80Smarks 844ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 845ecd6cf80Smarks } 846ecd6cf80Smarks 8474445fffbSMatthew Ahrens /* ARGSUSED */ 848ecd6cf80Smarks static int 8494445fffbSMatthew Ahrens zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 850ecd6cf80Smarks { 851ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 852ecd6cf80Smarks } 853ecd6cf80Smarks 854cbf6f6aaSWilliam Gorrell /* 855cbf6f6aaSWilliam Gorrell * Destroying snapshots with delegated permissions requires 8564445fffbSMatthew Ahrens * descendant mount and destroy permissions. 857cbf6f6aaSWilliam Gorrell */ 8584445fffbSMatthew Ahrens /* ARGSUSED */ 859cbf6f6aaSWilliam Gorrell static int 8604445fffbSMatthew Ahrens zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 861cbf6f6aaSWilliam Gorrell { 8624445fffbSMatthew Ahrens nvlist_t *snaps; 8634445fffbSMatthew Ahrens nvpair_t *pair, *nextpair; 8644445fffbSMatthew Ahrens int error = 0; 865cbf6f6aaSWilliam Gorrell 8664445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 867be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 8684445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 8694445fffbSMatthew Ahrens pair = nextpair) { 8704445fffbSMatthew Ahrens nextpair = nvlist_next_nvpair(snaps, pair); 87178f17100SMatthew Ahrens error = zfs_secpolicy_destroy_perms(nvpair_name(pair), cr); 87278f17100SMatthew Ahrens if (error == ENOENT) { 8734445fffbSMatthew Ahrens /* 8744445fffbSMatthew Ahrens * Ignore any snapshots that don't exist (we consider 8754445fffbSMatthew Ahrens * them "already destroyed"). Remove the name from the 8764445fffbSMatthew Ahrens * nvl here in case the snapshot is created between 8774445fffbSMatthew Ahrens * now and when we try to destroy it (in which case 8784445fffbSMatthew Ahrens * we don't want to destroy it since we haven't 8794445fffbSMatthew Ahrens * checked for permission). 8804445fffbSMatthew Ahrens */ 8814445fffbSMatthew Ahrens fnvlist_remove_nvpair(snaps, pair); 8824445fffbSMatthew Ahrens error = 0; 8834445fffbSMatthew Ahrens } 8844445fffbSMatthew Ahrens if (error != 0) 8854445fffbSMatthew Ahrens break; 8864445fffbSMatthew Ahrens } 887cbf6f6aaSWilliam Gorrell 888cbf6f6aaSWilliam Gorrell return (error); 889cbf6f6aaSWilliam Gorrell } 890cbf6f6aaSWilliam Gorrell 891ecd6cf80Smarks int 892ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 893ecd6cf80Smarks { 8949adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 895ecd6cf80Smarks int error; 896ecd6cf80Smarks 897ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 898ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 899ecd6cf80Smarks return (error); 900ecd6cf80Smarks 901ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 902ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 903ecd6cf80Smarks return (error); 904ecd6cf80Smarks 905ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 906ecd6cf80Smarks sizeof (parentname))) != 0) 907ecd6cf80Smarks return (error); 908ecd6cf80Smarks 909ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 910ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 911ecd6cf80Smarks return (error); 912ecd6cf80Smarks 913ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 914ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 915ecd6cf80Smarks return (error); 916ecd6cf80Smarks 917ecd6cf80Smarks return (error); 918ecd6cf80Smarks } 919ecd6cf80Smarks 9204445fffbSMatthew Ahrens /* ARGSUSED */ 921ecd6cf80Smarks static int 9224445fffbSMatthew Ahrens zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 923ecd6cf80Smarks { 924ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 925ecd6cf80Smarks } 926ecd6cf80Smarks 9274445fffbSMatthew Ahrens /* ARGSUSED */ 928ecd6cf80Smarks static int 9294445fffbSMatthew Ahrens zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 930ecd6cf80Smarks { 9313b2aab18SMatthew Ahrens dsl_pool_t *dp; 9323b2aab18SMatthew Ahrens dsl_dataset_t *clone; 933ecd6cf80Smarks int error; 934ecd6cf80Smarks 935ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 936ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 9373b2aab18SMatthew Ahrens if (error != 0) 9383b2aab18SMatthew Ahrens return (error); 9393b2aab18SMatthew Ahrens 9403b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 9413b2aab18SMatthew Ahrens if (error != 0) 942ecd6cf80Smarks return (error); 943ecd6cf80Smarks 9443b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &clone); 945ecd6cf80Smarks 946ecd6cf80Smarks if (error == 0) { 9479adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 9483b2aab18SMatthew Ahrens dsl_dataset_t *origin = NULL; 949ecd6cf80Smarks dsl_dir_t *dd; 9503b2aab18SMatthew Ahrens dd = clone->ds_dir; 951ecd6cf80Smarks 952745cd3c5Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 953c1379625SJustin T. Gibbs dsl_dir_phys(dd)->dd_origin_obj, FTAG, &origin); 9543b2aab18SMatthew Ahrens if (error != 0) { 9553b2aab18SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 9563b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 957ecd6cf80Smarks return (error); 958ecd6cf80Smarks } 959ecd6cf80Smarks 9603b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms_ds(zc->zc_name, clone, 961ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 962ecd6cf80Smarks 9633b2aab18SMatthew Ahrens dsl_dataset_name(origin, parentname); 9643b2aab18SMatthew Ahrens if (error == 0) { 9653b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms_ds(parentname, origin, 966ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 9673b2aab18SMatthew Ahrens } 9683b2aab18SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 9693b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 970ecd6cf80Smarks } 9713b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 972ecd6cf80Smarks return (error); 973ecd6cf80Smarks } 974ecd6cf80Smarks 9754445fffbSMatthew Ahrens /* ARGSUSED */ 976ecd6cf80Smarks static int 9774445fffbSMatthew Ahrens zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 978ecd6cf80Smarks { 979ecd6cf80Smarks int error; 980ecd6cf80Smarks 981ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 982ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 983ecd6cf80Smarks return (error); 984ecd6cf80Smarks 985ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 986ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 987ecd6cf80Smarks return (error); 988ecd6cf80Smarks 989ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 990ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 991ecd6cf80Smarks } 992ecd6cf80Smarks 993ecd6cf80Smarks int 994ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 995ecd6cf80Smarks { 996681d9761SEric Taylor return (zfs_secpolicy_write_perms(name, 997681d9761SEric Taylor ZFS_DELEG_PERM_SNAPSHOT, cr)); 998ecd6cf80Smarks } 999ecd6cf80Smarks 10004445fffbSMatthew Ahrens /* 10014445fffbSMatthew Ahrens * Check for permission to create each snapshot in the nvlist. 10024445fffbSMatthew Ahrens */ 10034445fffbSMatthew Ahrens /* ARGSUSED */ 1004ecd6cf80Smarks static int 10054445fffbSMatthew Ahrens zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1006ecd6cf80Smarks { 10074445fffbSMatthew Ahrens nvlist_t *snaps; 1008d5285caeSGeorge Wilson int error = 0; 10094445fffbSMatthew Ahrens nvpair_t *pair; 1010ecd6cf80Smarks 10114445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 1012be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 10134445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 10144445fffbSMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 10154445fffbSMatthew Ahrens char *name = nvpair_name(pair); 10164445fffbSMatthew Ahrens char *atp = strchr(name, '@'); 10174445fffbSMatthew Ahrens 10184445fffbSMatthew Ahrens if (atp == NULL) { 1019be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 10204445fffbSMatthew Ahrens break; 10214445fffbSMatthew Ahrens } 10224445fffbSMatthew Ahrens *atp = '\0'; 10234445fffbSMatthew Ahrens error = zfs_secpolicy_snapshot_perms(name, cr); 10244445fffbSMatthew Ahrens *atp = '@'; 10254445fffbSMatthew Ahrens if (error != 0) 10264445fffbSMatthew Ahrens break; 10274445fffbSMatthew Ahrens } 10284445fffbSMatthew Ahrens return (error); 1029ecd6cf80Smarks } 1030ecd6cf80Smarks 103178f17100SMatthew Ahrens /* 103278f17100SMatthew Ahrens * Check for permission to create each snapshot in the nvlist. 103378f17100SMatthew Ahrens */ 103478f17100SMatthew Ahrens /* ARGSUSED */ 103578f17100SMatthew Ahrens static int 103678f17100SMatthew Ahrens zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 103778f17100SMatthew Ahrens { 103878f17100SMatthew Ahrens int error = 0; 103978f17100SMatthew Ahrens 104078f17100SMatthew Ahrens for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL); 104178f17100SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) { 104278f17100SMatthew Ahrens char *name = nvpair_name(pair); 104378f17100SMatthew Ahrens char *hashp = strchr(name, '#'); 104478f17100SMatthew Ahrens 104578f17100SMatthew Ahrens if (hashp == NULL) { 104678f17100SMatthew Ahrens error = SET_ERROR(EINVAL); 104778f17100SMatthew Ahrens break; 104878f17100SMatthew Ahrens } 104978f17100SMatthew Ahrens *hashp = '\0'; 105078f17100SMatthew Ahrens error = zfs_secpolicy_write_perms(name, 105178f17100SMatthew Ahrens ZFS_DELEG_PERM_BOOKMARK, cr); 105278f17100SMatthew Ahrens *hashp = '#'; 105378f17100SMatthew Ahrens if (error != 0) 105478f17100SMatthew Ahrens break; 105578f17100SMatthew Ahrens } 105678f17100SMatthew Ahrens return (error); 105778f17100SMatthew Ahrens } 105878f17100SMatthew Ahrens 10595cabbc6bSPrashanth Sreenivasa /* ARGSUSED */ 10605cabbc6bSPrashanth Sreenivasa static int 10615cabbc6bSPrashanth Sreenivasa zfs_secpolicy_remap(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 10625cabbc6bSPrashanth Sreenivasa { 10635cabbc6bSPrashanth Sreenivasa return (zfs_secpolicy_write_perms(zc->zc_name, 10645cabbc6bSPrashanth Sreenivasa ZFS_DELEG_PERM_REMAP, cr)); 10655cabbc6bSPrashanth Sreenivasa } 10665cabbc6bSPrashanth Sreenivasa 106778f17100SMatthew Ahrens /* ARGSUSED */ 106878f17100SMatthew Ahrens static int 106978f17100SMatthew Ahrens zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 107078f17100SMatthew Ahrens { 107178f17100SMatthew Ahrens nvpair_t *pair, *nextpair; 107278f17100SMatthew Ahrens int error = 0; 107378f17100SMatthew Ahrens 107478f17100SMatthew Ahrens for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL; 107578f17100SMatthew Ahrens pair = nextpair) { 107678f17100SMatthew Ahrens char *name = nvpair_name(pair); 107778f17100SMatthew Ahrens char *hashp = strchr(name, '#'); 107878f17100SMatthew Ahrens nextpair = nvlist_next_nvpair(innvl, pair); 107978f17100SMatthew Ahrens 108078f17100SMatthew Ahrens if (hashp == NULL) { 108178f17100SMatthew Ahrens error = SET_ERROR(EINVAL); 108278f17100SMatthew Ahrens break; 108378f17100SMatthew Ahrens } 108478f17100SMatthew Ahrens 108578f17100SMatthew Ahrens *hashp = '\0'; 108678f17100SMatthew Ahrens error = zfs_secpolicy_write_perms(name, 108778f17100SMatthew Ahrens ZFS_DELEG_PERM_DESTROY, cr); 108878f17100SMatthew Ahrens *hashp = '#'; 108978f17100SMatthew Ahrens if (error == ENOENT) { 109078f17100SMatthew Ahrens /* 109178f17100SMatthew Ahrens * Ignore any filesystems that don't exist (we consider 109278f17100SMatthew Ahrens * their bookmarks "already destroyed"). Remove 109378f17100SMatthew Ahrens * the name from the nvl here in case the filesystem 109478f17100SMatthew Ahrens * is created between now and when we try to destroy 109578f17100SMatthew Ahrens * the bookmark (in which case we don't want to 109678f17100SMatthew Ahrens * destroy it since we haven't checked for permission). 109778f17100SMatthew Ahrens */ 109878f17100SMatthew Ahrens fnvlist_remove_nvpair(innvl, pair); 109978f17100SMatthew Ahrens error = 0; 110078f17100SMatthew Ahrens } 110178f17100SMatthew Ahrens if (error != 0) 110278f17100SMatthew Ahrens break; 110378f17100SMatthew Ahrens } 110478f17100SMatthew Ahrens 110578f17100SMatthew Ahrens return (error); 110678f17100SMatthew Ahrens } 110778f17100SMatthew Ahrens 11084445fffbSMatthew Ahrens /* ARGSUSED */ 1109ecd6cf80Smarks static int 11104445fffbSMatthew Ahrens zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 11114445fffbSMatthew Ahrens { 11124445fffbSMatthew Ahrens /* 11134445fffbSMatthew Ahrens * Even root must have a proper TSD so that we know what pool 11144445fffbSMatthew Ahrens * to log to. 11154445fffbSMatthew Ahrens */ 11164445fffbSMatthew Ahrens if (tsd_get(zfs_allow_log_key) == NULL) 1117be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 11184445fffbSMatthew Ahrens return (0); 11194445fffbSMatthew Ahrens } 11204445fffbSMatthew Ahrens 11214445fffbSMatthew Ahrens static int 11224445fffbSMatthew Ahrens zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1123ecd6cf80Smarks { 11249adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 112592241e0bSTom Erickson int error; 11264445fffbSMatthew Ahrens char *origin; 1127ecd6cf80Smarks 1128ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 1129ecd6cf80Smarks sizeof (parentname))) != 0) 1130ecd6cf80Smarks return (error); 1131fa9e4066Sahrens 11324445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "origin", &origin) == 0 && 11334445fffbSMatthew Ahrens (error = zfs_secpolicy_write_perms(origin, 11344445fffbSMatthew Ahrens ZFS_DELEG_PERM_CLONE, cr)) != 0) 11354445fffbSMatthew Ahrens return (error); 1136fa9e4066Sahrens 1137ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 1138ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 1139ecd6cf80Smarks return (error); 1140ecd6cf80Smarks 11414445fffbSMatthew Ahrens return (zfs_secpolicy_write_perms(parentname, 11424445fffbSMatthew Ahrens ZFS_DELEG_PERM_MOUNT, cr)); 1143fa9e4066Sahrens } 1144fa9e4066Sahrens 1145fa9e4066Sahrens /* 1146fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 1147fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 1148fa9e4066Sahrens */ 1149fa9e4066Sahrens /* ARGSUSED */ 1150fa9e4066Sahrens static int 11514445fffbSMatthew Ahrens zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1152fa9e4066Sahrens { 1153fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 1154be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 1155fa9e4066Sahrens 1156fa9e4066Sahrens return (0); 1157fa9e4066Sahrens } 1158fa9e4066Sahrens 115999d5e173STim Haley /* 116099d5e173STim Haley * Policy for object to name lookups. 116199d5e173STim Haley */ 116299d5e173STim Haley /* ARGSUSED */ 116399d5e173STim Haley static int 11644445fffbSMatthew Ahrens zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 116599d5e173STim Haley { 116699d5e173STim Haley int error; 116799d5e173STim Haley 116899d5e173STim Haley if ((error = secpolicy_sys_config(cr, B_FALSE)) == 0) 116999d5e173STim Haley return (0); 117099d5e173STim Haley 117199d5e173STim Haley error = zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_DIFF, cr); 117299d5e173STim Haley return (error); 117399d5e173STim Haley } 117499d5e173STim Haley 1175ea8dc4b6Seschrock /* 1176ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 1177ea8dc4b6Seschrock */ 1178ea8dc4b6Seschrock /* ARGSUSED */ 1179ea8dc4b6Seschrock static int 11804445fffbSMatthew Ahrens zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1181ea8dc4b6Seschrock { 1182ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 1183ea8dc4b6Seschrock } 1184ea8dc4b6Seschrock 11854445fffbSMatthew Ahrens /* ARGSUSED */ 1186e45ce728Sahrens static int 11874445fffbSMatthew Ahrens zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1188e45ce728Sahrens { 1189e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 1190e45ce728Sahrens 1191990b4856Slling if (prop == ZPROP_INVAL) { 1192e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 1193be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1194e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 1195e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 1196e45ce728Sahrens } else { 119792241e0bSTom Erickson return (zfs_secpolicy_setprop(zc->zc_name, prop, 119892241e0bSTom Erickson NULL, cr)); 1199e45ce728Sahrens } 1200e45ce728Sahrens } 1201e45ce728Sahrens 120214843421SMatthew Ahrens static int 12034445fffbSMatthew Ahrens zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 120414843421SMatthew Ahrens { 12054445fffbSMatthew Ahrens int err = zfs_secpolicy_read(zc, innvl, cr); 120614843421SMatthew Ahrens if (err) 120714843421SMatthew Ahrens return (err); 120814843421SMatthew Ahrens 120914843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 1210be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 121114843421SMatthew Ahrens 121214843421SMatthew Ahrens if (zc->zc_value[0] == 0) { 121314843421SMatthew Ahrens /* 121414843421SMatthew Ahrens * They are asking about a posix uid/gid. If it's 121514843421SMatthew Ahrens * themself, allow it. 121614843421SMatthew Ahrens */ 121714843421SMatthew Ahrens if (zc->zc_objset_type == ZFS_PROP_USERUSED || 1218f67950b2SNasf-Fan zc->zc_objset_type == ZFS_PROP_USERQUOTA || 1219f67950b2SNasf-Fan zc->zc_objset_type == ZFS_PROP_USEROBJUSED || 1220f67950b2SNasf-Fan zc->zc_objset_type == ZFS_PROP_USEROBJQUOTA) { 122114843421SMatthew Ahrens if (zc->zc_guid == crgetuid(cr)) 122214843421SMatthew Ahrens return (0); 1223f67950b2SNasf-Fan } else if (zc->zc_objset_type == ZFS_PROP_GROUPUSED || 1224f67950b2SNasf-Fan zc->zc_objset_type == ZFS_PROP_GROUPQUOTA || 1225f67950b2SNasf-Fan zc->zc_objset_type == ZFS_PROP_GROUPOBJUSED || 1226f67950b2SNasf-Fan zc->zc_objset_type == ZFS_PROP_GROUPOBJQUOTA) { 122714843421SMatthew Ahrens if (groupmember(zc->zc_guid, cr)) 122814843421SMatthew Ahrens return (0); 122914843421SMatthew Ahrens } 1230f67950b2SNasf-Fan /* else is for project quota/used */ 123114843421SMatthew Ahrens } 123214843421SMatthew Ahrens 123314843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 123414843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 123514843421SMatthew Ahrens } 123614843421SMatthew Ahrens 123714843421SMatthew Ahrens static int 12384445fffbSMatthew Ahrens zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 123914843421SMatthew Ahrens { 12404445fffbSMatthew Ahrens int err = zfs_secpolicy_read(zc, innvl, cr); 124114843421SMatthew Ahrens if (err) 124214843421SMatthew Ahrens return (err); 124314843421SMatthew Ahrens 124414843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 1245be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 124614843421SMatthew Ahrens 124714843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 124814843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 124914843421SMatthew Ahrens } 125014843421SMatthew Ahrens 12514445fffbSMatthew Ahrens /* ARGSUSED */ 125214843421SMatthew Ahrens static int 12534445fffbSMatthew Ahrens zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 125414843421SMatthew Ahrens { 125592241e0bSTom Erickson return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, 125692241e0bSTom Erickson NULL, cr)); 125714843421SMatthew Ahrens } 125814843421SMatthew Ahrens 12594445fffbSMatthew Ahrens /* ARGSUSED */ 1260842727c2SChris Kirby static int 12614445fffbSMatthew Ahrens zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1262842727c2SChris Kirby { 12633b2aab18SMatthew Ahrens nvpair_t *pair; 12643b2aab18SMatthew Ahrens nvlist_t *holds; 12653b2aab18SMatthew Ahrens int error; 12663b2aab18SMatthew Ahrens 12673b2aab18SMatthew Ahrens error = nvlist_lookup_nvlist(innvl, "holds", &holds); 12683b2aab18SMatthew Ahrens if (error != 0) 1269be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 12703b2aab18SMatthew Ahrens 12713b2aab18SMatthew Ahrens for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; 12723b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(holds, pair)) { 12739adfa60dSMatthew Ahrens char fsname[ZFS_MAX_DATASET_NAME_LEN]; 12743b2aab18SMatthew Ahrens error = dmu_fsname(nvpair_name(pair), fsname); 12753b2aab18SMatthew Ahrens if (error != 0) 12763b2aab18SMatthew Ahrens return (error); 12773b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms(fsname, 12783b2aab18SMatthew Ahrens ZFS_DELEG_PERM_HOLD, cr); 12793b2aab18SMatthew Ahrens if (error != 0) 12803b2aab18SMatthew Ahrens return (error); 12813b2aab18SMatthew Ahrens } 12823b2aab18SMatthew Ahrens return (0); 1283842727c2SChris Kirby } 1284842727c2SChris Kirby 12854445fffbSMatthew Ahrens /* ARGSUSED */ 1286842727c2SChris Kirby static int 12874445fffbSMatthew Ahrens zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1288842727c2SChris Kirby { 12893b2aab18SMatthew Ahrens nvpair_t *pair; 12903b2aab18SMatthew Ahrens int error; 12913b2aab18SMatthew Ahrens 12923b2aab18SMatthew Ahrens for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL; 12933b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(innvl, pair)) { 12949adfa60dSMatthew Ahrens char fsname[ZFS_MAX_DATASET_NAME_LEN]; 12953b2aab18SMatthew Ahrens error = dmu_fsname(nvpair_name(pair), fsname); 12963b2aab18SMatthew Ahrens if (error != 0) 12973b2aab18SMatthew Ahrens return (error); 12983b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms(fsname, 12993b2aab18SMatthew Ahrens ZFS_DELEG_PERM_RELEASE, cr); 13003b2aab18SMatthew Ahrens if (error != 0) 13013b2aab18SMatthew Ahrens return (error); 13023b2aab18SMatthew Ahrens } 13033b2aab18SMatthew Ahrens return (0); 1304842727c2SChris Kirby } 1305842727c2SChris Kirby 1306eb633035STom Caputi /* ARGSUSED */ 1307eb633035STom Caputi static int 1308eb633035STom Caputi zfs_secpolicy_load_key(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1309eb633035STom Caputi { 1310eb633035STom Caputi return (zfs_secpolicy_write_perms(zc->zc_name, 1311eb633035STom Caputi ZFS_DELEG_PERM_LOAD_KEY, cr)); 1312eb633035STom Caputi } 1313eb633035STom Caputi 1314eb633035STom Caputi /* ARGSUSED */ 1315eb633035STom Caputi static int 1316eb633035STom Caputi zfs_secpolicy_change_key(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1317eb633035STom Caputi { 1318eb633035STom Caputi return (zfs_secpolicy_write_perms(zc->zc_name, 1319eb633035STom Caputi ZFS_DELEG_PERM_CHANGE_KEY, cr)); 1320eb633035STom Caputi } 1321eb633035STom Caputi 132299d5e173STim Haley /* 132399d5e173STim Haley * Policy for allowing temporary snapshots to be taken or released 132499d5e173STim Haley */ 132599d5e173STim Haley static int 13264445fffbSMatthew Ahrens zfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 132799d5e173STim Haley { 132899d5e173STim Haley /* 132999d5e173STim Haley * A temporary snapshot is the same as a snapshot, 133099d5e173STim Haley * hold, destroy and release all rolled into one. 133199d5e173STim Haley * Delegated diff alone is sufficient that we allow this. 133299d5e173STim Haley */ 133399d5e173STim Haley int error; 133499d5e173STim Haley 133599d5e173STim Haley if ((error = zfs_secpolicy_write_perms(zc->zc_name, 133699d5e173STim Haley ZFS_DELEG_PERM_DIFF, cr)) == 0) 133799d5e173STim Haley return (0); 133899d5e173STim Haley 13394445fffbSMatthew Ahrens error = zfs_secpolicy_snapshot_perms(zc->zc_name, cr); 13403b2aab18SMatthew Ahrens if (error == 0) 13414445fffbSMatthew Ahrens error = zfs_secpolicy_hold(zc, innvl, cr); 13423b2aab18SMatthew Ahrens if (error == 0) 13434445fffbSMatthew Ahrens error = zfs_secpolicy_release(zc, innvl, cr); 13443b2aab18SMatthew Ahrens if (error == 0) 13454445fffbSMatthew Ahrens error = zfs_secpolicy_destroy(zc, innvl, cr); 134699d5e173STim Haley return (error); 134799d5e173STim Haley } 134899d5e173STim Haley 1349fa9e4066Sahrens /* 1350fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 1351fa9e4066Sahrens */ 1352fa9e4066Sahrens static int 1353478ed9adSEric Taylor get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) 1354fa9e4066Sahrens { 1355fa9e4066Sahrens char *packed; 1356fa9e4066Sahrens int error; 1357990b4856Slling nvlist_t *list = NULL; 1358fa9e4066Sahrens 1359fa9e4066Sahrens /* 1360e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 1361fa9e4066Sahrens */ 1362990b4856Slling if (size == 0) 1363be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1364fa9e4066Sahrens 1365fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 1366fa9e4066Sahrens 1367478ed9adSEric Taylor if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 1368478ed9adSEric Taylor iflag)) != 0) { 1369fa9e4066Sahrens kmem_free(packed, size); 1370c71c00bbSRichard Yao return (SET_ERROR(EFAULT)); 1371fa9e4066Sahrens } 1372fa9e4066Sahrens 1373990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 1374fa9e4066Sahrens kmem_free(packed, size); 1375fa9e4066Sahrens return (error); 1376fa9e4066Sahrens } 1377fa9e4066Sahrens 1378fa9e4066Sahrens kmem_free(packed, size); 1379fa9e4066Sahrens 1380990b4856Slling *nvp = list; 1381fa9e4066Sahrens return (0); 1382fa9e4066Sahrens } 1383fa9e4066Sahrens 13844445fffbSMatthew Ahrens /* 13854445fffbSMatthew Ahrens * Reduce the size of this nvlist until it can be serialized in 'max' bytes. 13864445fffbSMatthew Ahrens * Entries will be removed from the end of the nvlist, and one int32 entry 13874445fffbSMatthew Ahrens * named "N_MORE_ERRORS" will be added indicating how many entries were 13884445fffbSMatthew Ahrens * removed. 13894445fffbSMatthew Ahrens */ 139092241e0bSTom Erickson static int 13914445fffbSMatthew Ahrens nvlist_smush(nvlist_t *errors, size_t max) 139292241e0bSTom Erickson { 139392241e0bSTom Erickson size_t size; 139492241e0bSTom Erickson 13954445fffbSMatthew Ahrens size = fnvlist_size(errors); 139692241e0bSTom Erickson 13974445fffbSMatthew Ahrens if (size > max) { 139892241e0bSTom Erickson nvpair_t *more_errors; 139992241e0bSTom Erickson int n = 0; 140092241e0bSTom Erickson 14014445fffbSMatthew Ahrens if (max < 1024) 1402be6fd75aSMatthew Ahrens return (SET_ERROR(ENOMEM)); 140392241e0bSTom Erickson 14044445fffbSMatthew Ahrens fnvlist_add_int32(errors, ZPROP_N_MORE_ERRORS, 0); 14054445fffbSMatthew Ahrens more_errors = nvlist_prev_nvpair(errors, NULL); 140692241e0bSTom Erickson 140792241e0bSTom Erickson do { 14084445fffbSMatthew Ahrens nvpair_t *pair = nvlist_prev_nvpair(errors, 140992241e0bSTom Erickson more_errors); 14104445fffbSMatthew Ahrens fnvlist_remove_nvpair(errors, pair); 141192241e0bSTom Erickson n++; 14124445fffbSMatthew Ahrens size = fnvlist_size(errors); 14134445fffbSMatthew Ahrens } while (size > max); 141492241e0bSTom Erickson 14154445fffbSMatthew Ahrens fnvlist_remove_nvpair(errors, more_errors); 14164445fffbSMatthew Ahrens fnvlist_add_int32(errors, ZPROP_N_MORE_ERRORS, n); 14174445fffbSMatthew Ahrens ASSERT3U(fnvlist_size(errors), <=, max); 141892241e0bSTom Erickson } 141992241e0bSTom Erickson 142092241e0bSTom Erickson return (0); 142192241e0bSTom Erickson } 142292241e0bSTom Erickson 1423e9dbad6fSeschrock static int 1424e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 1425e9dbad6fSeschrock { 1426e9dbad6fSeschrock char *packed = NULL; 14276e27f868SSam Falkner int error = 0; 1428e9dbad6fSeschrock size_t size; 1429e9dbad6fSeschrock 14304445fffbSMatthew Ahrens size = fnvlist_size(nvl); 1431e9dbad6fSeschrock 1432e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 1433be6fd75aSMatthew Ahrens error = SET_ERROR(ENOMEM); 1434e9dbad6fSeschrock } else { 14354445fffbSMatthew Ahrens packed = fnvlist_pack(nvl, &size); 14366e27f868SSam Falkner if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 14376e27f868SSam Falkner size, zc->zc_iflags) != 0) 1438be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 14394445fffbSMatthew Ahrens fnvlist_pack_free(packed, size); 1440e9dbad6fSeschrock } 1441e9dbad6fSeschrock 1442e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 14434445fffbSMatthew Ahrens zc->zc_nvlist_dst_filled = B_TRUE; 1444e9dbad6fSeschrock return (error); 1445e9dbad6fSeschrock } 1446e9dbad6fSeschrock 1447dfc11533SChris Williamson int 1448dfc11533SChris Williamson getzfsvfs_impl(objset_t *os, zfsvfs_t **zfvp) 144914843421SMatthew Ahrens { 1450dfc11533SChris Williamson int error = 0; 1451503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 1452be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1453503ad85cSMatthew Ahrens } 145414843421SMatthew Ahrens 1455503ad85cSMatthew Ahrens mutex_enter(&os->os_user_ptr_lock); 1456af4c679fSSean McEnroe *zfvp = dmu_objset_get_user(os); 1457af4c679fSSean McEnroe if (*zfvp) { 1458af4c679fSSean McEnroe VFS_HOLD((*zfvp)->z_vfs); 145914843421SMatthew Ahrens } else { 1460be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 146114843421SMatthew Ahrens } 1462503ad85cSMatthew Ahrens mutex_exit(&os->os_user_ptr_lock); 1463dfc11533SChris Williamson return (error); 1464dfc11533SChris Williamson } 1465dfc11533SChris Williamson 1466ed992b0aSSerapheim Dimitropoulos int 1467dfc11533SChris Williamson getzfsvfs(const char *dsname, zfsvfs_t **zfvp) 1468dfc11533SChris Williamson { 1469dfc11533SChris Williamson objset_t *os; 1470dfc11533SChris Williamson int error; 1471dfc11533SChris Williamson 1472dfc11533SChris Williamson error = dmu_objset_hold(dsname, FTAG, &os); 1473dfc11533SChris Williamson if (error != 0) 1474dfc11533SChris Williamson return (error); 1475dfc11533SChris Williamson 1476dfc11533SChris Williamson error = getzfsvfs_impl(os, zfvp); 1477503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 147814843421SMatthew Ahrens return (error); 147914843421SMatthew Ahrens } 148014843421SMatthew Ahrens 148114843421SMatthew Ahrens /* 148214843421SMatthew Ahrens * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 148314843421SMatthew Ahrens * case its z_vfs will be NULL, and it will be opened as the owner. 1484ad135b5dSChristopher Siden * If 'writer' is set, the z_teardown_lock will be held for RW_WRITER, 1485ad135b5dSChristopher Siden * which prevents all vnode ops from running. 148614843421SMatthew Ahrens */ 148714843421SMatthew Ahrens static int 14881412a1a2SMark Shellenbaum zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer) 148914843421SMatthew Ahrens { 149014843421SMatthew Ahrens int error = 0; 149114843421SMatthew Ahrens 1492af4c679fSSean McEnroe if (getzfsvfs(name, zfvp) != 0) 1493af4c679fSSean McEnroe error = zfsvfs_create(name, zfvp); 149414843421SMatthew Ahrens if (error == 0) { 1495c9030f6cSAlexander Motin rrm_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER : 14961412a1a2SMark Shellenbaum RW_READER, tag); 1497af4c679fSSean McEnroe if ((*zfvp)->z_unmounted) { 149814843421SMatthew Ahrens /* 149914843421SMatthew Ahrens * XXX we could probably try again, since the unmounting 150014843421SMatthew Ahrens * thread should be just about to disassociate the 150114843421SMatthew Ahrens * objset from the zfsvfs. 150214843421SMatthew Ahrens */ 1503c9030f6cSAlexander Motin rrm_exit(&(*zfvp)->z_teardown_lock, tag); 1504be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 150514843421SMatthew Ahrens } 150614843421SMatthew Ahrens } 150714843421SMatthew Ahrens return (error); 150814843421SMatthew Ahrens } 150914843421SMatthew Ahrens 151014843421SMatthew Ahrens static void 151114843421SMatthew Ahrens zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 151214843421SMatthew Ahrens { 1513c9030f6cSAlexander Motin rrm_exit(&zfsvfs->z_teardown_lock, tag); 151414843421SMatthew Ahrens 151514843421SMatthew Ahrens if (zfsvfs->z_vfs) { 151614843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 151714843421SMatthew Ahrens } else { 1518eb633035STom Caputi dmu_objset_disown(zfsvfs->z_os, B_TRUE, zfsvfs); 151914843421SMatthew Ahrens zfsvfs_free(zfsvfs); 152014843421SMatthew Ahrens } 152114843421SMatthew Ahrens } 152214843421SMatthew Ahrens 1523fa9e4066Sahrens static int 1524fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 1525fa9e4066Sahrens { 1526fa9e4066Sahrens int error; 1527990b4856Slling nvlist_t *config, *props = NULL; 15280a48a24eStimh nvlist_t *rootprops = NULL; 15290a48a24eStimh nvlist_t *zplprops = NULL; 153004e56356SAndriy Gapon char *spa_name = zc->zc_name; 1531eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 1532fa9e4066Sahrens 1533990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1534478ed9adSEric Taylor zc->zc_iflags, &config)) 1535fa9e4066Sahrens return (error); 15362a6b87f0Sek 1537990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 1538478ed9adSEric Taylor get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1539478ed9adSEric Taylor zc->zc_iflags, &props))) { 1540990b4856Slling nvlist_free(config); 1541990b4856Slling return (error); 1542990b4856Slling } 1543990b4856Slling 15440a48a24eStimh if (props) { 15450a48a24eStimh nvlist_t *nvl = NULL; 1546eb633035STom Caputi nvlist_t *hidden_args = NULL; 15470a48a24eStimh uint64_t version = SPA_VERSION; 154804e56356SAndriy Gapon char *tname; 15490a48a24eStimh 15500a48a24eStimh (void) nvlist_lookup_uint64(props, 15510a48a24eStimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 1552ad135b5dSChristopher Siden if (!SPA_VERSION_IS_SUPPORTED(version)) { 1553be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 15540a48a24eStimh goto pool_props_bad; 15550a48a24eStimh } 15560a48a24eStimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 15570a48a24eStimh if (nvl) { 15580a48a24eStimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 15590a48a24eStimh if (error != 0) { 15600a48a24eStimh nvlist_free(config); 15610a48a24eStimh nvlist_free(props); 15620a48a24eStimh return (error); 15630a48a24eStimh } 15640a48a24eStimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 15650a48a24eStimh } 1566eb633035STom Caputi 1567eb633035STom Caputi (void) nvlist_lookup_nvlist(props, ZPOOL_HIDDEN_ARGS, 1568eb633035STom Caputi &hidden_args); 1569eb633035STom Caputi error = dsl_crypto_params_create_nvlist(DCP_CMD_NONE, 1570eb633035STom Caputi rootprops, hidden_args, &dcp); 1571eb633035STom Caputi if (error != 0) { 1572eb633035STom Caputi nvlist_free(config); 1573eb633035STom Caputi nvlist_free(props); 1574eb633035STom Caputi return (error); 1575eb633035STom Caputi } 1576eb633035STom Caputi (void) nvlist_remove_all(props, ZPOOL_HIDDEN_ARGS); 1577eb633035STom Caputi 15780a48a24eStimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 15790a48a24eStimh error = zfs_fill_zplprops_root(version, rootprops, 15800a48a24eStimh zplprops, NULL); 15813b2aab18SMatthew Ahrens if (error != 0) 15820a48a24eStimh goto pool_props_bad; 158304e56356SAndriy Gapon 158404e56356SAndriy Gapon if (nvlist_lookup_string(props, 158504e56356SAndriy Gapon zpool_prop_to_name(ZPOOL_PROP_TNAME), &tname) == 0) 158604e56356SAndriy Gapon spa_name = tname; 15870a48a24eStimh } 15880a48a24eStimh 1589eb633035STom Caputi error = spa_create(zc->zc_name, config, props, zplprops, dcp); 15900a48a24eStimh 15910a48a24eStimh /* 15920a48a24eStimh * Set the remaining root properties 15930a48a24eStimh */ 159404e56356SAndriy Gapon if (!error && (error = zfs_set_prop_nvlist(spa_name, 159592241e0bSTom Erickson ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) 159604e56356SAndriy Gapon (void) spa_destroy(spa_name); 1597fa9e4066Sahrens 15980a48a24eStimh pool_props_bad: 15990a48a24eStimh nvlist_free(rootprops); 16000a48a24eStimh nvlist_free(zplprops); 1601fa9e4066Sahrens nvlist_free(config); 16020a48a24eStimh nvlist_free(props); 1603eb633035STom Caputi dsl_crypto_params_free(dcp, !!error); 1604990b4856Slling 1605fa9e4066Sahrens return (error); 1606fa9e4066Sahrens } 1607fa9e4066Sahrens 1608fa9e4066Sahrens static int 1609fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 1610fa9e4066Sahrens { 1611ecd6cf80Smarks int error; 1612ecd6cf80Smarks zfs_log_history(zc); 1613ecd6cf80Smarks error = spa_destroy(zc->zc_name); 1614681d9761SEric Taylor if (error == 0) 1615681d9761SEric Taylor zvol_remove_minors(zc->zc_name); 1616ecd6cf80Smarks return (error); 1617fa9e4066Sahrens } 1618fa9e4066Sahrens 1619fa9e4066Sahrens static int 1620fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 1621fa9e4066Sahrens { 1622990b4856Slling nvlist_t *config, *props = NULL; 1623fa9e4066Sahrens uint64_t guid; 1624468c413aSTim Haley int error; 1625fa9e4066Sahrens 1626990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1627478ed9adSEric Taylor zc->zc_iflags, &config)) != 0) 1628990b4856Slling return (error); 1629990b4856Slling 1630990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 1631478ed9adSEric Taylor get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1632478ed9adSEric Taylor zc->zc_iflags, &props))) { 1633990b4856Slling nvlist_free(config); 1634fa9e4066Sahrens return (error); 1635990b4856Slling } 1636fa9e4066Sahrens 1637fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 1638ea8dc4b6Seschrock guid != zc->zc_guid) 1639be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 1640fa9e4066Sahrens else 16414b964adaSGeorge Wilson error = spa_import(zc->zc_name, config, props, zc->zc_cookie); 1642fa9e4066Sahrens 16434b964adaSGeorge Wilson if (zc->zc_nvlist_dst != 0) { 16444b964adaSGeorge Wilson int err; 16454b964adaSGeorge Wilson 16464b964adaSGeorge Wilson if ((err = put_nvlist(zc, config)) != 0) 16474b964adaSGeorge Wilson error = err; 16484b964adaSGeorge Wilson } 1649468c413aSTim Haley 1650fa9e4066Sahrens nvlist_free(config); 1651fa9e4066Sahrens 1652aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 1653990b4856Slling 1654fa9e4066Sahrens return (error); 1655fa9e4066Sahrens } 1656fa9e4066Sahrens 1657fa9e4066Sahrens static int 1658fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 1659fa9e4066Sahrens { 1660ecd6cf80Smarks int error; 166189a89ebfSlling boolean_t force = (boolean_t)zc->zc_cookie; 1662394ab0cbSGeorge Wilson boolean_t hardforce = (boolean_t)zc->zc_guid; 166389a89ebfSlling 1664ecd6cf80Smarks zfs_log_history(zc); 1665394ab0cbSGeorge Wilson error = spa_export(zc->zc_name, NULL, force, hardforce); 1666681d9761SEric Taylor if (error == 0) 1667681d9761SEric Taylor zvol_remove_minors(zc->zc_name); 1668ecd6cf80Smarks return (error); 1669fa9e4066Sahrens } 1670fa9e4066Sahrens 1671fa9e4066Sahrens static int 1672fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 1673fa9e4066Sahrens { 1674fa9e4066Sahrens nvlist_t *configs; 1675fa9e4066Sahrens int error; 1676fa9e4066Sahrens 1677fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1678be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 1679fa9e4066Sahrens 1680e9dbad6fSeschrock error = put_nvlist(zc, configs); 1681fa9e4066Sahrens 1682fa9e4066Sahrens nvlist_free(configs); 1683fa9e4066Sahrens 1684fa9e4066Sahrens return (error); 1685fa9e4066Sahrens } 1686fa9e4066Sahrens 1687ad135b5dSChristopher Siden /* 1688ad135b5dSChristopher Siden * inputs: 1689ad135b5dSChristopher Siden * zc_name name of the pool 1690ad135b5dSChristopher Siden * 1691ad135b5dSChristopher Siden * outputs: 1692ad135b5dSChristopher Siden * zc_cookie real errno 1693ad135b5dSChristopher Siden * zc_nvlist_dst config nvlist 1694ad135b5dSChristopher Siden * zc_nvlist_dst_size size of config nvlist 1695ad135b5dSChristopher Siden */ 1696fa9e4066Sahrens static int 1697fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 1698fa9e4066Sahrens { 1699fa9e4066Sahrens nvlist_t *config; 1700fa9e4066Sahrens int error; 1701ea8dc4b6Seschrock int ret = 0; 1702fa9e4066Sahrens 1703e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 1704e9dbad6fSeschrock sizeof (zc->zc_value)); 1705fa9e4066Sahrens 1706fa9e4066Sahrens if (config != NULL) { 1707e9dbad6fSeschrock ret = put_nvlist(zc, config); 1708fa9e4066Sahrens nvlist_free(config); 1709ea8dc4b6Seschrock 1710ea8dc4b6Seschrock /* 1711ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 1712ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 1713ea8dc4b6Seschrock * in 'zc_cookie'. 1714ea8dc4b6Seschrock */ 1715ea8dc4b6Seschrock zc->zc_cookie = error; 1716fa9e4066Sahrens } else { 1717ea8dc4b6Seschrock ret = error; 1718fa9e4066Sahrens } 1719fa9e4066Sahrens 1720ea8dc4b6Seschrock return (ret); 1721fa9e4066Sahrens } 1722fa9e4066Sahrens 1723fa9e4066Sahrens /* 1724fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 1725fa9e4066Sahrens * user land knows which devices are available and overall pool health. 1726fa9e4066Sahrens */ 1727fa9e4066Sahrens static int 1728fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1729fa9e4066Sahrens { 1730fa9e4066Sahrens nvlist_t *tryconfig, *config; 1731fa9e4066Sahrens int error; 1732fa9e4066Sahrens 1733990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1734478ed9adSEric Taylor zc->zc_iflags, &tryconfig)) != 0) 1735fa9e4066Sahrens return (error); 1736fa9e4066Sahrens 1737fa9e4066Sahrens config = spa_tryimport(tryconfig); 1738fa9e4066Sahrens 1739fa9e4066Sahrens nvlist_free(tryconfig); 1740fa9e4066Sahrens 1741fa9e4066Sahrens if (config == NULL) 1742be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1743fa9e4066Sahrens 1744e9dbad6fSeschrock error = put_nvlist(zc, config); 1745fa9e4066Sahrens nvlist_free(config); 1746fa9e4066Sahrens 1747fa9e4066Sahrens return (error); 1748fa9e4066Sahrens } 1749fa9e4066Sahrens 17503f9d6ad7SLin Ling /* 17513f9d6ad7SLin Ling * inputs: 17523f9d6ad7SLin Ling * zc_name name of the pool 17533f9d6ad7SLin Ling * zc_cookie scan func (pool_scan_func_t) 17541702cce7SAlek Pinchuk * zc_flags scrub pause/resume flag (pool_scrub_cmd_t) 17553f9d6ad7SLin Ling */ 1756fa9e4066Sahrens static int 17573f9d6ad7SLin Ling zfs_ioc_pool_scan(zfs_cmd_t *zc) 1758fa9e4066Sahrens { 1759fa9e4066Sahrens spa_t *spa; 1760fa9e4066Sahrens int error; 1761fa9e4066Sahrens 176206eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 176306eeb2adSek return (error); 176406eeb2adSek 17651702cce7SAlek Pinchuk if (zc->zc_flags >= POOL_SCRUB_FLAGS_END) 17661702cce7SAlek Pinchuk return (SET_ERROR(EINVAL)); 17671702cce7SAlek Pinchuk 17681702cce7SAlek Pinchuk if (zc->zc_flags == POOL_SCRUB_PAUSE) 17691702cce7SAlek Pinchuk error = spa_scrub_pause_resume(spa, POOL_SCRUB_PAUSE); 17701702cce7SAlek Pinchuk else if (zc->zc_cookie == POOL_SCAN_NONE) 17713f9d6ad7SLin Ling error = spa_scan_stop(spa); 17723f9d6ad7SLin Ling else 17733f9d6ad7SLin Ling error = spa_scan(spa, zc->zc_cookie); 177406eeb2adSek 177506eeb2adSek spa_close(spa, FTAG); 177606eeb2adSek 1777fa9e4066Sahrens return (error); 1778fa9e4066Sahrens } 1779fa9e4066Sahrens 1780fa9e4066Sahrens static int 1781fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 1782fa9e4066Sahrens { 1783fa9e4066Sahrens spa_t *spa; 1784fa9e4066Sahrens int error; 1785fa9e4066Sahrens 1786fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1787fa9e4066Sahrens if (error == 0) { 1788fa9e4066Sahrens spa_freeze(spa); 1789fa9e4066Sahrens spa_close(spa, FTAG); 1790fa9e4066Sahrens } 1791fa9e4066Sahrens return (error); 1792fa9e4066Sahrens } 1793fa9e4066Sahrens 1794eaca9bbdSeschrock static int 1795eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 1796eaca9bbdSeschrock { 1797eaca9bbdSeschrock spa_t *spa; 1798eaca9bbdSeschrock int error; 1799eaca9bbdSeschrock 180006eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 180106eeb2adSek return (error); 180206eeb2adSek 1803ad135b5dSChristopher Siden if (zc->zc_cookie < spa_version(spa) || 1804ad135b5dSChristopher Siden !SPA_VERSION_IS_SUPPORTED(zc->zc_cookie)) { 1805558d2d50Slling spa_close(spa, FTAG); 1806be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1807558d2d50Slling } 1808558d2d50Slling 1809990b4856Slling spa_upgrade(spa, zc->zc_cookie); 181006eeb2adSek spa_close(spa, FTAG); 181106eeb2adSek 181206eeb2adSek return (error); 181306eeb2adSek } 181406eeb2adSek 181506eeb2adSek static int 181606eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 181706eeb2adSek { 181806eeb2adSek spa_t *spa; 181906eeb2adSek char *hist_buf; 182006eeb2adSek uint64_t size; 182106eeb2adSek int error; 182206eeb2adSek 182306eeb2adSek if ((size = zc->zc_history_len) == 0) 1824be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 182506eeb2adSek 182606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 182706eeb2adSek return (error); 182806eeb2adSek 1829e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1830d7306b64Sek spa_close(spa, FTAG); 1831be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 1832d7306b64Sek } 1833d7306b64Sek 183406eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 183506eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 183606eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 1837478ed9adSEric Taylor error = ddi_copyout(hist_buf, 1838478ed9adSEric Taylor (void *)(uintptr_t)zc->zc_history, 1839478ed9adSEric Taylor zc->zc_history_len, zc->zc_iflags); 184006eeb2adSek } 184106eeb2adSek 184206eeb2adSek spa_close(spa, FTAG); 184306eeb2adSek kmem_free(hist_buf, size); 184406eeb2adSek return (error); 184506eeb2adSek } 184606eeb2adSek 1847e9103aaeSGarrett D'Amore static int 1848e9103aaeSGarrett D'Amore zfs_ioc_pool_reguid(zfs_cmd_t *zc) 1849e9103aaeSGarrett D'Amore { 1850e9103aaeSGarrett D'Amore spa_t *spa; 1851e9103aaeSGarrett D'Amore int error; 1852e9103aaeSGarrett D'Amore 1853e9103aaeSGarrett D'Amore error = spa_open(zc->zc_name, &spa, FTAG); 1854e9103aaeSGarrett D'Amore if (error == 0) { 1855e9103aaeSGarrett D'Amore error = spa_change_guid(spa); 1856e9103aaeSGarrett D'Amore spa_close(spa, FTAG); 1857e9103aaeSGarrett D'Amore } 1858e9103aaeSGarrett D'Amore return (error); 1859e9103aaeSGarrett D'Amore } 1860e9103aaeSGarrett D'Amore 186155434c77Sek static int 186255434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 186355434c77Sek { 18643b2aab18SMatthew Ahrens return (dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)); 186555434c77Sek } 186655434c77Sek 1867503ad85cSMatthew Ahrens /* 1868503ad85cSMatthew Ahrens * inputs: 1869503ad85cSMatthew Ahrens * zc_name name of filesystem 1870503ad85cSMatthew Ahrens * zc_obj object to find 1871503ad85cSMatthew Ahrens * 1872503ad85cSMatthew Ahrens * outputs: 1873503ad85cSMatthew Ahrens * zc_value name of object 1874503ad85cSMatthew Ahrens */ 187555434c77Sek static int 187655434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 187755434c77Sek { 1878503ad85cSMatthew Ahrens objset_t *os; 187955434c77Sek int error; 188055434c77Sek 1881503ad85cSMatthew Ahrens /* XXX reading from objset not owned */ 1882eb633035STom Caputi if ((error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, 1883eb633035STom Caputi FTAG, &os)) != 0) 188455434c77Sek return (error); 1885503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 1886eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 1887be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1888503ad85cSMatthew Ahrens } 1889503ad85cSMatthew Ahrens error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value, 189055434c77Sek sizeof (zc->zc_value)); 1891eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 189255434c77Sek 189355434c77Sek return (error); 189455434c77Sek } 189555434c77Sek 189699d5e173STim Haley /* 189799d5e173STim Haley * inputs: 189899d5e173STim Haley * zc_name name of filesystem 189999d5e173STim Haley * zc_obj object to find 190099d5e173STim Haley * 190199d5e173STim Haley * outputs: 190299d5e173STim Haley * zc_stat stats on object 190399d5e173STim Haley * zc_value path to object 190499d5e173STim Haley */ 190599d5e173STim Haley static int 190699d5e173STim Haley zfs_ioc_obj_to_stats(zfs_cmd_t *zc) 190799d5e173STim Haley { 190899d5e173STim Haley objset_t *os; 190999d5e173STim Haley int error; 191099d5e173STim Haley 191199d5e173STim Haley /* XXX reading from objset not owned */ 1912eb633035STom Caputi if ((error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, 1913eb633035STom Caputi FTAG, &os)) != 0) 191499d5e173STim Haley return (error); 191599d5e173STim Haley if (dmu_objset_type(os) != DMU_OST_ZFS) { 1916eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 1917be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 191899d5e173STim Haley } 191999d5e173STim Haley error = zfs_obj_to_stats(os, zc->zc_obj, &zc->zc_stat, zc->zc_value, 192099d5e173STim Haley sizeof (zc->zc_value)); 1921eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 192299d5e173STim Haley 192399d5e173STim Haley return (error); 192499d5e173STim Haley } 192599d5e173STim Haley 1926fa9e4066Sahrens static int 1927fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1928fa9e4066Sahrens { 1929fa9e4066Sahrens spa_t *spa; 1930fa9e4066Sahrens int error; 1931e7cbe64fSgw nvlist_t *config, **l2cache, **spares; 1932e7cbe64fSgw uint_t nl2cache = 0, nspares = 0; 1933fa9e4066Sahrens 1934fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1935fa9e4066Sahrens if (error != 0) 1936fa9e4066Sahrens return (error); 1937fa9e4066Sahrens 1938fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1939478ed9adSEric Taylor zc->zc_iflags, &config); 1940fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1941fa94a07fSbrendan &l2cache, &nl2cache); 1942fa94a07fSbrendan 1943e7cbe64fSgw (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1944e7cbe64fSgw &spares, &nspares); 1945e7cbe64fSgw 1946b1b8ab34Slling /* 1947b1b8ab34Slling * A root pool with concatenated devices is not supported. 1948e7cbe64fSgw * Thus, can not add a device to a root pool. 1949e7cbe64fSgw * 1950e7cbe64fSgw * Intent log device can not be added to a rootpool because 1951e7cbe64fSgw * during mountroot, zil is replayed, a seperated log device 1952e7cbe64fSgw * can not be accessed during the mountroot time. 1953e7cbe64fSgw * 1954e7cbe64fSgw * l2cache and spare devices are ok to be added to a rootpool. 1955b1b8ab34Slling */ 1956b24ab676SJeff Bonwick if (spa_bootfs(spa) != 0 && nl2cache == 0 && nspares == 0) { 19571195e687SMark J Musante nvlist_free(config); 1958b1b8ab34Slling spa_close(spa, FTAG); 1959be6fd75aSMatthew Ahrens return (SET_ERROR(EDOM)); 1960b1b8ab34Slling } 1961b1b8ab34Slling 1962fa94a07fSbrendan if (error == 0) { 1963fa9e4066Sahrens error = spa_vdev_add(spa, config); 1964fa9e4066Sahrens nvlist_free(config); 1965fa9e4066Sahrens } 1966fa9e4066Sahrens spa_close(spa, FTAG); 1967fa9e4066Sahrens return (error); 1968fa9e4066Sahrens } 1969fa9e4066Sahrens 19703f9d6ad7SLin Ling /* 19713f9d6ad7SLin Ling * inputs: 19723f9d6ad7SLin Ling * zc_name name of the pool 19735cabbc6bSPrashanth Sreenivasa * zc_guid guid of vdev to remove 19745cabbc6bSPrashanth Sreenivasa * zc_cookie cancel removal 19753f9d6ad7SLin Ling */ 1976fa9e4066Sahrens static int 1977fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1978fa9e4066Sahrens { 197999653d4eSeschrock spa_t *spa; 198099653d4eSeschrock int error; 198199653d4eSeschrock 198299653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 198399653d4eSeschrock if (error != 0) 198499653d4eSeschrock return (error); 19855cabbc6bSPrashanth Sreenivasa if (zc->zc_cookie != 0) { 19865cabbc6bSPrashanth Sreenivasa error = spa_vdev_remove_cancel(spa); 19875cabbc6bSPrashanth Sreenivasa } else { 19885cabbc6bSPrashanth Sreenivasa error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 19895cabbc6bSPrashanth Sreenivasa } 199099653d4eSeschrock spa_close(spa, FTAG); 199199653d4eSeschrock return (error); 1992fa9e4066Sahrens } 1993fa9e4066Sahrens 1994fa9e4066Sahrens static int 19953d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1996fa9e4066Sahrens { 1997fa9e4066Sahrens spa_t *spa; 1998fa9e4066Sahrens int error; 19993d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 2000fa9e4066Sahrens 200106eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2002fa9e4066Sahrens return (error); 20033d7072f8Seschrock switch (zc->zc_cookie) { 20043d7072f8Seschrock case VDEV_STATE_ONLINE: 20053d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 20063d7072f8Seschrock break; 2007fa9e4066Sahrens 20083d7072f8Seschrock case VDEV_STATE_OFFLINE: 20093d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 20103d7072f8Seschrock break; 2011fa9e4066Sahrens 20123d7072f8Seschrock case VDEV_STATE_FAULTED: 2013069f55e2SEric Schrock if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 2014069f55e2SEric Schrock zc->zc_obj != VDEV_AUX_EXTERNAL) 2015069f55e2SEric Schrock zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 2016069f55e2SEric Schrock 2017069f55e2SEric Schrock error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); 20183d7072f8Seschrock break; 20193d7072f8Seschrock 20203d7072f8Seschrock case VDEV_STATE_DEGRADED: 2021069f55e2SEric Schrock if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 2022069f55e2SEric Schrock zc->zc_obj != VDEV_AUX_EXTERNAL) 2023069f55e2SEric Schrock zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 2024069f55e2SEric Schrock 2025069f55e2SEric Schrock error = vdev_degrade(spa, zc->zc_guid, zc->zc_obj); 20263d7072f8Seschrock break; 20273d7072f8Seschrock 20283d7072f8Seschrock default: 2029be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 20303d7072f8Seschrock } 20313d7072f8Seschrock zc->zc_cookie = newstate; 2032fa9e4066Sahrens spa_close(spa, FTAG); 2033fa9e4066Sahrens return (error); 2034fa9e4066Sahrens } 2035fa9e4066Sahrens 2036fa9e4066Sahrens static int 2037fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 2038fa9e4066Sahrens { 2039fa9e4066Sahrens spa_t *spa; 2040fa9e4066Sahrens int replacing = zc->zc_cookie; 2041fa9e4066Sahrens nvlist_t *config; 2042fa9e4066Sahrens int error; 2043fa9e4066Sahrens 204406eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2045fa9e4066Sahrens return (error); 2046fa9e4066Sahrens 2047990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 2048478ed9adSEric Taylor zc->zc_iflags, &config)) == 0) { 2049ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 2050fa9e4066Sahrens nvlist_free(config); 2051fa9e4066Sahrens } 2052fa9e4066Sahrens 2053fa9e4066Sahrens spa_close(spa, FTAG); 2054fa9e4066Sahrens return (error); 2055fa9e4066Sahrens } 2056fa9e4066Sahrens 2057fa9e4066Sahrens static int 2058fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 2059fa9e4066Sahrens { 2060fa9e4066Sahrens spa_t *spa; 2061fa9e4066Sahrens int error; 2062fa9e4066Sahrens 206306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2064fa9e4066Sahrens return (error); 2065fa9e4066Sahrens 20668ad4d6ddSJeff Bonwick error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 2067fa9e4066Sahrens 2068fa9e4066Sahrens spa_close(spa, FTAG); 2069fa9e4066Sahrens return (error); 2070fa9e4066Sahrens } 2071fa9e4066Sahrens 20721195e687SMark J Musante static int 20731195e687SMark J Musante zfs_ioc_vdev_split(zfs_cmd_t *zc) 20741195e687SMark J Musante { 20751195e687SMark J Musante spa_t *spa; 20761195e687SMark J Musante nvlist_t *config, *props = NULL; 20771195e687SMark J Musante int error; 20781195e687SMark J Musante boolean_t exp = !!(zc->zc_cookie & ZPOOL_EXPORT_AFTER_SPLIT); 20791195e687SMark J Musante 20801195e687SMark J Musante if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 20811195e687SMark J Musante return (error); 20821195e687SMark J Musante 20831195e687SMark J Musante if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 20841195e687SMark J Musante zc->zc_iflags, &config)) { 20851195e687SMark J Musante spa_close(spa, FTAG); 20861195e687SMark J Musante return (error); 20871195e687SMark J Musante } 20881195e687SMark J Musante 20891195e687SMark J Musante if (zc->zc_nvlist_src_size != 0 && (error = 20901195e687SMark J Musante get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 20911195e687SMark J Musante zc->zc_iflags, &props))) { 20921195e687SMark J Musante spa_close(spa, FTAG); 20931195e687SMark J Musante nvlist_free(config); 20941195e687SMark J Musante return (error); 20951195e687SMark J Musante } 20961195e687SMark J Musante 20971195e687SMark J Musante error = spa_vdev_split_mirror(spa, zc->zc_string, config, props, exp); 20981195e687SMark J Musante 20991195e687SMark J Musante spa_close(spa, FTAG); 21001195e687SMark J Musante 21011195e687SMark J Musante nvlist_free(config); 21021195e687SMark J Musante nvlist_free(props); 21031195e687SMark J Musante 21041195e687SMark J Musante return (error); 21051195e687SMark J Musante } 21061195e687SMark J Musante 2107c67d9675Seschrock static int 2108c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 2109c67d9675Seschrock { 2110c67d9675Seschrock spa_t *spa; 2111e9dbad6fSeschrock char *path = zc->zc_value; 2112ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 2113c67d9675Seschrock int error; 2114c67d9675Seschrock 2115c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 2116c67d9675Seschrock if (error != 0) 2117c67d9675Seschrock return (error); 2118c67d9675Seschrock 2119c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 2120c67d9675Seschrock spa_close(spa, FTAG); 2121c67d9675Seschrock return (error); 2122c67d9675Seschrock } 2123c67d9675Seschrock 21246809eb4eSEric Schrock static int 21256809eb4eSEric Schrock zfs_ioc_vdev_setfru(zfs_cmd_t *zc) 21266809eb4eSEric Schrock { 21276809eb4eSEric Schrock spa_t *spa; 21286809eb4eSEric Schrock char *fru = zc->zc_value; 21296809eb4eSEric Schrock uint64_t guid = zc->zc_guid; 21306809eb4eSEric Schrock int error; 21316809eb4eSEric Schrock 21326809eb4eSEric Schrock error = spa_open(zc->zc_name, &spa, FTAG); 21336809eb4eSEric Schrock if (error != 0) 21346809eb4eSEric Schrock return (error); 21356809eb4eSEric Schrock 21366809eb4eSEric Schrock error = spa_vdev_setfru(spa, guid, fru); 21376809eb4eSEric Schrock spa_close(spa, FTAG); 21386809eb4eSEric Schrock return (error); 21396809eb4eSEric Schrock } 21406809eb4eSEric Schrock 2141fa9e4066Sahrens static int 2142a7f53a56SChris Kirby zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) 2143fa9e4066Sahrens { 2144a7f53a56SChris Kirby int error = 0; 21457f7322feSeschrock nvlist_t *nv; 2146fa9e4066Sahrens 2147a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 2148fa9e4066Sahrens 21495ad82045Snd if (zc->zc_nvlist_dst != 0 && 215092241e0bSTom Erickson (error = dsl_prop_get_all(os, &nv)) == 0) { 2151a2eea2e1Sahrens dmu_objset_stats(os, nv); 2152432f72fdSahrens /* 2153bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 2154432f72fdSahrens * which we aren't supposed to do with a 2155745cd3c5Smaybee * DS_MODE_USER hold, because it could be 2156432f72fdSahrens * inconsistent. So this is a bit of a workaround... 2157503ad85cSMatthew Ahrens * XXX reading with out owning 2158432f72fdSahrens */ 215919b94df9SMatthew Ahrens if (!zc->zc_objset_stats.dds_inconsistent && 216019b94df9SMatthew Ahrens dmu_objset_type(os) == DMU_OST_ZVOL) { 216119b94df9SMatthew Ahrens error = zvol_get_stats(os, nv); 216219b94df9SMatthew Ahrens if (error == EIO) 216319b94df9SMatthew Ahrens return (error); 2164fb09f5aaSMadhav Suresh VERIFY0(error); 2165e7437265Sahrens } 2166e9dbad6fSeschrock error = put_nvlist(zc, nv); 21677f7322feSeschrock nvlist_free(nv); 21687f7322feSeschrock } 2169fa9e4066Sahrens 2170a7f53a56SChris Kirby return (error); 2171a7f53a56SChris Kirby } 2172a7f53a56SChris Kirby 2173a7f53a56SChris Kirby /* 2174a7f53a56SChris Kirby * inputs: 2175a7f53a56SChris Kirby * zc_name name of filesystem 2176a7f53a56SChris Kirby * zc_nvlist_dst_size size of buffer for property nvlist 2177a7f53a56SChris Kirby * 2178a7f53a56SChris Kirby * outputs: 2179a7f53a56SChris Kirby * zc_objset_stats stats 2180a7f53a56SChris Kirby * zc_nvlist_dst property nvlist 2181a7f53a56SChris Kirby * zc_nvlist_dst_size size of property nvlist 2182a7f53a56SChris Kirby */ 2183a7f53a56SChris Kirby static int 2184a7f53a56SChris Kirby zfs_ioc_objset_stats(zfs_cmd_t *zc) 2185a7f53a56SChris Kirby { 21863b2aab18SMatthew Ahrens objset_t *os; 2187a7f53a56SChris Kirby int error; 2188a7f53a56SChris Kirby 21893b2aab18SMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &os); 21903b2aab18SMatthew Ahrens if (error == 0) { 21913b2aab18SMatthew Ahrens error = zfs_ioc_objset_stats_impl(zc, os); 21923b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 21933b2aab18SMatthew Ahrens } 2194a7f53a56SChris Kirby 2195fa9e4066Sahrens return (error); 2196fa9e4066Sahrens } 2197fa9e4066Sahrens 219892241e0bSTom Erickson /* 219992241e0bSTom Erickson * inputs: 220092241e0bSTom Erickson * zc_name name of filesystem 220192241e0bSTom Erickson * zc_nvlist_dst_size size of buffer for property nvlist 220292241e0bSTom Erickson * 220392241e0bSTom Erickson * outputs: 220492241e0bSTom Erickson * zc_nvlist_dst received property nvlist 220592241e0bSTom Erickson * zc_nvlist_dst_size size of received property nvlist 220692241e0bSTom Erickson * 220792241e0bSTom Erickson * Gets received properties (distinct from local properties on or after 220892241e0bSTom Erickson * SPA_VERSION_RECVD_PROPS) for callers who want to differentiate received from 220992241e0bSTom Erickson * local property values. 221092241e0bSTom Erickson */ 221192241e0bSTom Erickson static int 221292241e0bSTom Erickson zfs_ioc_objset_recvd_props(zfs_cmd_t *zc) 221392241e0bSTom Erickson { 22143b2aab18SMatthew Ahrens int error = 0; 221592241e0bSTom Erickson nvlist_t *nv; 221692241e0bSTom Erickson 221792241e0bSTom Erickson /* 221892241e0bSTom Erickson * Without this check, we would return local property values if the 221992241e0bSTom Erickson * caller has not already received properties on or after 222092241e0bSTom Erickson * SPA_VERSION_RECVD_PROPS. 222192241e0bSTom Erickson */ 22223b2aab18SMatthew Ahrens if (!dsl_prop_get_hasrecvd(zc->zc_name)) 2223be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 222492241e0bSTom Erickson 222592241e0bSTom Erickson if (zc->zc_nvlist_dst != 0 && 22263b2aab18SMatthew Ahrens (error = dsl_prop_get_received(zc->zc_name, &nv)) == 0) { 222792241e0bSTom Erickson error = put_nvlist(zc, nv); 222892241e0bSTom Erickson nvlist_free(nv); 222992241e0bSTom Erickson } 223092241e0bSTom Erickson 223192241e0bSTom Erickson return (error); 223292241e0bSTom Erickson } 223392241e0bSTom Erickson 2234de8267e0Stimh static int 2235de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 2236de8267e0Stimh { 2237de8267e0Stimh uint64_t value; 2238de8267e0Stimh int error; 2239de8267e0Stimh 2240de8267e0Stimh /* 2241de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 2242de8267e0Stimh * the default value (if there is one). 2243de8267e0Stimh */ 2244de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 2245de8267e0Stimh return (error); 2246de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 2247de8267e0Stimh return (0); 2248de8267e0Stimh } 2249de8267e0Stimh 22503cb34c60Sahrens /* 22513cb34c60Sahrens * inputs: 22523cb34c60Sahrens * zc_name name of filesystem 2253de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 22543cb34c60Sahrens * 22553cb34c60Sahrens * outputs: 2256de8267e0Stimh * zc_nvlist_dst zpl property nvlist 2257de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 22583cb34c60Sahrens */ 2259bd00f61bSrm static int 2260de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 2261bd00f61bSrm { 2262de8267e0Stimh objset_t *os; 2263de8267e0Stimh int err; 2264bd00f61bSrm 2265503ad85cSMatthew Ahrens /* XXX reading without owning */ 2266503ad85cSMatthew Ahrens if (err = dmu_objset_hold(zc->zc_name, FTAG, &os)) 2267de8267e0Stimh return (err); 2268bd00f61bSrm 2269bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 2270bd00f61bSrm 2271bd00f61bSrm /* 2272de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 2273745cd3c5Smaybee * which we aren't supposed to do with a DS_MODE_USER 2274745cd3c5Smaybee * hold, because it could be inconsistent. 2275bd00f61bSrm */ 2276dd328bf6SToomas Soome if (zc->zc_nvlist_dst != 0 && 2277de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 2278de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 2279de8267e0Stimh nvlist_t *nv; 2280de8267e0Stimh 2281de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2282de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 2283de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 2284de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 2285de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 2286de8267e0Stimh err = put_nvlist(zc, nv); 2287de8267e0Stimh nvlist_free(nv); 2288de8267e0Stimh } else { 2289be6fd75aSMatthew Ahrens err = SET_ERROR(ENOENT); 2290de8267e0Stimh } 2291503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2292de8267e0Stimh return (err); 2293bd00f61bSrm } 2294bd00f61bSrm 229514843421SMatthew Ahrens static boolean_t 229614843421SMatthew Ahrens dataset_name_hidden(const char *name) 229714843421SMatthew Ahrens { 229814843421SMatthew Ahrens /* 229914843421SMatthew Ahrens * Skip over datasets that are not visible in this zone, 230014843421SMatthew Ahrens * internal datasets (which have a $ in their name), and 230114843421SMatthew Ahrens * temporary datasets (which have a % in their name). 230214843421SMatthew Ahrens */ 230314843421SMatthew Ahrens if (strchr(name, '$') != NULL) 230414843421SMatthew Ahrens return (B_TRUE); 230514843421SMatthew Ahrens if (strchr(name, '%') != NULL) 230614843421SMatthew Ahrens return (B_TRUE); 230714843421SMatthew Ahrens if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL)) 230814843421SMatthew Ahrens return (B_TRUE); 230914843421SMatthew Ahrens return (B_FALSE); 231014843421SMatthew Ahrens } 231114843421SMatthew Ahrens 2312de8267e0Stimh /* 2313de8267e0Stimh * inputs: 2314de8267e0Stimh * zc_name name of filesystem 2315de8267e0Stimh * zc_cookie zap cursor 2316de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 2317de8267e0Stimh * 2318de8267e0Stimh * outputs: 2319de8267e0Stimh * zc_name name of next filesystem 232014843421SMatthew Ahrens * zc_cookie zap cursor 2321de8267e0Stimh * zc_objset_stats stats 2322de8267e0Stimh * zc_nvlist_dst property nvlist 2323de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 2324de8267e0Stimh */ 2325fa9e4066Sahrens static int 2326fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 2327fa9e4066Sahrens { 232887e5029aSahrens objset_t *os; 2329fa9e4066Sahrens int error; 2330fa9e4066Sahrens char *p; 2331620252bcSChris Kirby size_t orig_len = strlen(zc->zc_name); 2332fa9e4066Sahrens 2333620252bcSChris Kirby top: 2334503ad85cSMatthew Ahrens if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) { 233587e5029aSahrens if (error == ENOENT) 2336be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 233787e5029aSahrens return (error); 2338fa9e4066Sahrens } 2339fa9e4066Sahrens 2340fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 2341fa9e4066Sahrens if (p == NULL || p[1] != '\0') 2342fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 2343fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 2344fa9e4066Sahrens 2345fa9e4066Sahrens do { 234687e5029aSahrens error = dmu_dir_list_next(os, 234787e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 234887e5029aSahrens NULL, &zc->zc_cookie); 2349fa9e4066Sahrens if (error == ENOENT) 2350be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 235119b94df9SMatthew Ahrens } while (error == 0 && dataset_name_hidden(zc->zc_name)); 2352503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2353fa9e4066Sahrens 2354681d9761SEric Taylor /* 2355681d9761SEric Taylor * If it's an internal dataset (ie. with a '$' in its name), 2356681d9761SEric Taylor * don't try to get stats for it, otherwise we'll return ENOENT. 2357681d9761SEric Taylor */ 2358620252bcSChris Kirby if (error == 0 && strchr(zc->zc_name, '$') == NULL) { 235987e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 2360620252bcSChris Kirby if (error == ENOENT) { 2361620252bcSChris Kirby /* We lost a race with destroy, get the next one. */ 2362620252bcSChris Kirby zc->zc_name[orig_len] = '\0'; 2363620252bcSChris Kirby goto top; 2364620252bcSChris Kirby } 2365620252bcSChris Kirby } 2366fa9e4066Sahrens return (error); 2367fa9e4066Sahrens } 2368fa9e4066Sahrens 23693cb34c60Sahrens /* 23703cb34c60Sahrens * inputs: 23713cb34c60Sahrens * zc_name name of filesystem 23723cb34c60Sahrens * zc_cookie zap cursor 23733cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 23740d8fa8f8SMartin Matuska * zc_simple when set, only name is requested 23753cb34c60Sahrens * 23763cb34c60Sahrens * outputs: 23773cb34c60Sahrens * zc_name name of next snapshot 23783cb34c60Sahrens * zc_objset_stats stats 23793cb34c60Sahrens * zc_nvlist_dst property nvlist 23803cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 23813cb34c60Sahrens */ 2382fa9e4066Sahrens static int 2383fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 2384fa9e4066Sahrens { 238587e5029aSahrens objset_t *os; 2386fa9e4066Sahrens int error; 2387fa9e4066Sahrens 2388503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &os); 23893b2aab18SMatthew Ahrens if (error != 0) { 2390745cd3c5Smaybee return (error == ENOENT ? ESRCH : error); 23913b2aab18SMatthew Ahrens } 2392fa9e4066Sahrens 2393b81d61a6Slling /* 2394b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 2395b81d61a6Slling * so exit immediately. 2396b81d61a6Slling */ 23979adfa60dSMatthew Ahrens if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= 23989adfa60dSMatthew Ahrens ZFS_MAX_DATASET_NAME_LEN) { 2399503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2400be6fd75aSMatthew Ahrens return (SET_ERROR(ESRCH)); 2401fa9e4066Sahrens } 2402fa9e4066Sahrens 240387e5029aSahrens error = dmu_snapshot_list_next(os, 240487e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 2405a7f53a56SChris Kirby zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie, 2406a7f53a56SChris Kirby NULL); 2407a7f53a56SChris Kirby 24080d8fa8f8SMartin Matuska if (error == 0 && !zc->zc_simple) { 2409a7f53a56SChris Kirby dsl_dataset_t *ds; 2410a7f53a56SChris Kirby dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool; 2411a7f53a56SChris Kirby 2412a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds); 24133b2aab18SMatthew Ahrens if (error == 0) { 2414a7f53a56SChris Kirby objset_t *ossnap; 2415a7f53a56SChris Kirby 2416a7f53a56SChris Kirby error = dmu_objset_from_ds(ds, &ossnap); 2417a7f53a56SChris Kirby if (error == 0) 2418a7f53a56SChris Kirby error = zfs_ioc_objset_stats_impl(zc, ossnap); 2419a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 2420620252bcSChris Kirby } 2421620252bcSChris Kirby } else if (error == ENOENT) { 2422be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 2423620252bcSChris Kirby } 2424fa9e4066Sahrens 2425a7f53a56SChris Kirby dmu_objset_rele(os, FTAG); 24263cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 24273b2aab18SMatthew Ahrens if (error != 0) 24283cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 2429fa9e4066Sahrens return (error); 2430fa9e4066Sahrens } 2431fa9e4066Sahrens 243292241e0bSTom Erickson static int 243392241e0bSTom Erickson zfs_prop_set_userquota(const char *dsname, nvpair_t *pair) 2434fa9e4066Sahrens { 243592241e0bSTom Erickson const char *propname = nvpair_name(pair); 243692241e0bSTom Erickson uint64_t *valary; 243792241e0bSTom Erickson unsigned int vallen; 243892241e0bSTom Erickson const char *domain; 2439eeb85002STim Haley char *dash; 244092241e0bSTom Erickson zfs_userquota_prop_t type; 244192241e0bSTom Erickson uint64_t rid; 244292241e0bSTom Erickson uint64_t quota; 244392241e0bSTom Erickson zfsvfs_t *zfsvfs; 244492241e0bSTom Erickson int err; 244592241e0bSTom Erickson 244692241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 244792241e0bSTom Erickson nvlist_t *attrs; 244892241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2449eeb85002STim Haley if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2450eeb85002STim Haley &pair) != 0) 2451be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 245292241e0bSTom Erickson } 2453e9dbad6fSeschrock 2454ecd6cf80Smarks /* 2455eeb85002STim Haley * A correctly constructed propname is encoded as 245692241e0bSTom Erickson * userquota@<rid>-<domain>. 2457ecd6cf80Smarks */ 2458eeb85002STim Haley if ((dash = strchr(propname, '-')) == NULL || 2459eeb85002STim Haley nvpair_value_uint64_array(pair, &valary, &vallen) != 0 || 2460eeb85002STim Haley vallen != 3) 2461be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2462eeb85002STim Haley 2463eeb85002STim Haley domain = dash + 1; 2464eeb85002STim Haley type = valary[0]; 2465eeb85002STim Haley rid = valary[1]; 2466eeb85002STim Haley quota = valary[2]; 2467e9dbad6fSeschrock 24681412a1a2SMark Shellenbaum err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_FALSE); 246992241e0bSTom Erickson if (err == 0) { 247092241e0bSTom Erickson err = zfs_set_userquota(zfsvfs, type, domain, rid, quota); 247192241e0bSTom Erickson zfsvfs_rele(zfsvfs, FTAG); 247292241e0bSTom Erickson } 2473e9dbad6fSeschrock 247492241e0bSTom Erickson return (err); 247592241e0bSTom Erickson } 247614843421SMatthew Ahrens 247792241e0bSTom Erickson /* 247892241e0bSTom Erickson * If the named property is one that has a special function to set its value, 247992241e0bSTom Erickson * return 0 on success and a positive error code on failure; otherwise if it is 248092241e0bSTom Erickson * not one of the special properties handled by this function, return -1. 248192241e0bSTom Erickson * 2482eeb85002STim Haley * XXX: It would be better for callers of the property interface if we handled 248392241e0bSTom Erickson * these special cases in dsl_prop.c (in the dsl layer). 248492241e0bSTom Erickson */ 248592241e0bSTom Erickson static int 248692241e0bSTom Erickson zfs_prop_set_special(const char *dsname, zprop_source_t source, 248792241e0bSTom Erickson nvpair_t *pair) 248892241e0bSTom Erickson { 248992241e0bSTom Erickson const char *propname = nvpair_name(pair); 249092241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 2491eb633035STom Caputi uint64_t intval = 0; 2492eb633035STom Caputi char *strval = NULL; 2493b5152584SMatthew Ahrens int err = -1; 2494fa9e4066Sahrens 249592241e0bSTom Erickson if (prop == ZPROP_INVAL) { 249692241e0bSTom Erickson if (zfs_prop_userquota(propname)) 249792241e0bSTom Erickson return (zfs_prop_set_userquota(dsname, pair)); 249892241e0bSTom Erickson return (-1); 249992241e0bSTom Erickson } 250014843421SMatthew Ahrens 250192241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 250292241e0bSTom Erickson nvlist_t *attrs; 250392241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 250492241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 250592241e0bSTom Erickson &pair) == 0); 250692241e0bSTom Erickson } 2507db870a07Sahrens 2508eb633035STom Caputi /* all special properties are numeric except for keylocation */ 2509eb633035STom Caputi if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 2510eb633035STom Caputi strval = fnvpair_value_string(pair); 2511eb633035STom Caputi } else { 2512eb633035STom Caputi intval = fnvpair_value_uint64(pair); 2513eb633035STom Caputi } 251440feaa91Sahrens 251592241e0bSTom Erickson switch (prop) { 251692241e0bSTom Erickson case ZFS_PROP_QUOTA: 251792241e0bSTom Erickson err = dsl_dir_set_quota(dsname, source, intval); 251892241e0bSTom Erickson break; 251992241e0bSTom Erickson case ZFS_PROP_REFQUOTA: 25203b2aab18SMatthew Ahrens err = dsl_dataset_set_refquota(dsname, source, intval); 252192241e0bSTom Erickson break; 2522a2afb611SJerry Jelinek case ZFS_PROP_FILESYSTEM_LIMIT: 2523a2afb611SJerry Jelinek case ZFS_PROP_SNAPSHOT_LIMIT: 2524a2afb611SJerry Jelinek if (intval == UINT64_MAX) { 2525a2afb611SJerry Jelinek /* clearing the limit, just do it */ 2526a2afb611SJerry Jelinek err = 0; 2527a2afb611SJerry Jelinek } else { 2528a2afb611SJerry Jelinek err = dsl_dir_activate_fs_ss_limit(dsname); 2529a2afb611SJerry Jelinek } 2530eb633035STom Caputi /* 2531eb633035STom Caputi * Set err to -1 to force the zfs_set_prop_nvlist code down the 2532eb633035STom Caputi * default path to set the value in the nvlist. 2533eb633035STom Caputi */ 2534eb633035STom Caputi if (err == 0) 2535eb633035STom Caputi err = -1; 2536eb633035STom Caputi break; 2537eb633035STom Caputi case ZFS_PROP_KEYLOCATION: 2538eb633035STom Caputi err = dsl_crypto_can_set_keylocation(dsname, strval); 2539eb633035STom Caputi 2540a2afb611SJerry Jelinek /* 2541a2afb611SJerry Jelinek * Set err to -1 to force the zfs_set_prop_nvlist code down the 2542a2afb611SJerry Jelinek * default path to set the value in the nvlist. 2543a2afb611SJerry Jelinek */ 2544a2afb611SJerry Jelinek if (err == 0) 2545a2afb611SJerry Jelinek err = -1; 2546a2afb611SJerry Jelinek break; 254792241e0bSTom Erickson case ZFS_PROP_RESERVATION: 254892241e0bSTom Erickson err = dsl_dir_set_reservation(dsname, source, intval); 254992241e0bSTom Erickson break; 255092241e0bSTom Erickson case ZFS_PROP_REFRESERVATION: 25513b2aab18SMatthew Ahrens err = dsl_dataset_set_refreservation(dsname, source, intval); 255292241e0bSTom Erickson break; 255392241e0bSTom Erickson case ZFS_PROP_VOLSIZE: 2554c61ea566SGeorge Wilson err = zvol_set_volsize(dsname, intval); 255592241e0bSTom Erickson break; 255692241e0bSTom Erickson case ZFS_PROP_VERSION: 255792241e0bSTom Erickson { 255892241e0bSTom Erickson zfsvfs_t *zfsvfs; 25599e6eda55Smarks 25601412a1a2SMark Shellenbaum if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) 2561b24ab676SJeff Bonwick break; 2562b24ab676SJeff Bonwick 256392241e0bSTom Erickson err = zfs_set_version(zfsvfs, intval); 256492241e0bSTom Erickson zfsvfs_rele(zfsvfs, FTAG); 2565d0f3f37eSMark Shellenbaum 256692241e0bSTom Erickson if (err == 0 && intval >= ZPL_VERSION_USERSPACE) { 2567b16da2e2SGeorge Wilson zfs_cmd_t *zc; 2568b16da2e2SGeorge Wilson 2569b16da2e2SGeorge Wilson zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2570b16da2e2SGeorge Wilson (void) strcpy(zc->zc_name, dsname); 2571b16da2e2SGeorge Wilson (void) zfs_ioc_userspace_upgrade(zc); 2572f67950b2SNasf-Fan (void) zfs_ioc_id_quota_upgrade(zc); 2573b16da2e2SGeorge Wilson kmem_free(zc, sizeof (zfs_cmd_t)); 257440feaa91Sahrens } 257592241e0bSTom Erickson break; 2576ecd6cf80Smarks } 257792241e0bSTom Erickson default: 257892241e0bSTom Erickson err = -1; 257992241e0bSTom Erickson } 2580e9dbad6fSeschrock 258192241e0bSTom Erickson return (err); 258292241e0bSTom Erickson } 2583a9799022Sck 258492241e0bSTom Erickson /* 258592241e0bSTom Erickson * This function is best effort. If it fails to set any of the given properties, 25864445fffbSMatthew Ahrens * it continues to set as many as it can and returns the last error 25874445fffbSMatthew Ahrens * encountered. If the caller provides a non-NULL errlist, it will be filled in 25884445fffbSMatthew Ahrens * with the list of names of all the properties that failed along with the 25894445fffbSMatthew Ahrens * corresponding error numbers. 259092241e0bSTom Erickson * 25914445fffbSMatthew Ahrens * If every property is set successfully, zero is returned and errlist is not 25924445fffbSMatthew Ahrens * modified. 259392241e0bSTom Erickson */ 259492241e0bSTom Erickson int 259592241e0bSTom Erickson zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, 25964445fffbSMatthew Ahrens nvlist_t *errlist) 259792241e0bSTom Erickson { 259892241e0bSTom Erickson nvpair_t *pair; 259992241e0bSTom Erickson nvpair_t *propval; 260002e383d1STom Erickson int rv = 0; 260192241e0bSTom Erickson uint64_t intval; 260292241e0bSTom Erickson char *strval; 26034445fffbSMatthew Ahrens nvlist_t *genericnvl = fnvlist_alloc(); 26044445fffbSMatthew Ahrens nvlist_t *retrynvl = fnvlist_alloc(); 2605a9799022Sck 260692241e0bSTom Erickson retry: 260792241e0bSTom Erickson pair = NULL; 260892241e0bSTom Erickson while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 260992241e0bSTom Erickson const char *propname = nvpair_name(pair); 261092241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 2611cfa69fd2STom Erickson int err = 0; 2612e9dbad6fSeschrock 261392241e0bSTom Erickson /* decode the property value */ 261492241e0bSTom Erickson propval = pair; 261592241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 261692241e0bSTom Erickson nvlist_t *attrs; 26174445fffbSMatthew Ahrens attrs = fnvpair_value_nvlist(pair); 2618eeb85002STim Haley if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2619eeb85002STim Haley &propval) != 0) 2620be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 262114843421SMatthew Ahrens } 2622e9dbad6fSeschrock 262392241e0bSTom Erickson /* Validate value type */ 26246ccda740Sloli if (err == 0 && source == ZPROP_SRC_INHERITED) { 26256ccda740Sloli /* inherited properties are expected to be booleans */ 26266ccda740Sloli if (nvpair_type(propval) != DATA_TYPE_BOOLEAN) 26276ccda740Sloli err = SET_ERROR(EINVAL); 26286ccda740Sloli } else if (err == 0 && prop == ZPROP_INVAL) { 262992241e0bSTom Erickson if (zfs_prop_user(propname)) { 263092241e0bSTom Erickson if (nvpair_type(propval) != DATA_TYPE_STRING) 2631be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 263292241e0bSTom Erickson } else if (zfs_prop_userquota(propname)) { 263392241e0bSTom Erickson if (nvpair_type(propval) != 263492241e0bSTom Erickson DATA_TYPE_UINT64_ARRAY) 2635be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 263619b94df9SMatthew Ahrens } else { 2637be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 26384201a95eSRic Aleshire } 2639eeb85002STim Haley } else if (err == 0) { 264092241e0bSTom Erickson if (nvpair_type(propval) == DATA_TYPE_STRING) { 264192241e0bSTom Erickson if (zfs_prop_get_type(prop) != PROP_TYPE_STRING) 2642be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 264392241e0bSTom Erickson } else if (nvpair_type(propval) == DATA_TYPE_UINT64) { 2644a2eea2e1Sahrens const char *unused; 2645a2eea2e1Sahrens 26464445fffbSMatthew Ahrens intval = fnvpair_value_uint64(propval); 2647e9dbad6fSeschrock 2648e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 264991ebeef5Sahrens case PROP_TYPE_NUMBER: 2650e9dbad6fSeschrock break; 265191ebeef5Sahrens case PROP_TYPE_STRING: 2652be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 265392241e0bSTom Erickson break; 265491ebeef5Sahrens case PROP_TYPE_INDEX: 2655acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 265692241e0bSTom Erickson intval, &unused) != 0) 2657be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 2658e9dbad6fSeschrock break; 2659e9dbad6fSeschrock default: 2660e7437265Sahrens cmn_err(CE_PANIC, 2661e7437265Sahrens "unknown property type"); 2662e9dbad6fSeschrock } 2663e9dbad6fSeschrock } else { 2664be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 2665e9dbad6fSeschrock } 2666e9dbad6fSeschrock } 266792241e0bSTom Erickson 266892241e0bSTom Erickson /* Validate permissions */ 266992241e0bSTom Erickson if (err == 0) 267092241e0bSTom Erickson err = zfs_check_settable(dsname, pair, CRED()); 267192241e0bSTom Erickson 267292241e0bSTom Erickson if (err == 0) { 26736ccda740Sloli if (source == ZPROP_SRC_INHERITED) 26746ccda740Sloli err = -1; /* does not need special handling */ 26756ccda740Sloli else 26766ccda740Sloli err = zfs_prop_set_special(dsname, source, 26776ccda740Sloli pair); 267892241e0bSTom Erickson if (err == -1) { 267992241e0bSTom Erickson /* 268092241e0bSTom Erickson * For better performance we build up a list of 268192241e0bSTom Erickson * properties to set in a single transaction. 268292241e0bSTom Erickson */ 268392241e0bSTom Erickson err = nvlist_add_nvpair(genericnvl, pair); 268492241e0bSTom Erickson } else if (err != 0 && nvl != retrynvl) { 268592241e0bSTom Erickson /* 268692241e0bSTom Erickson * This may be a spurious error caused by 268792241e0bSTom Erickson * receiving quota and reservation out of order. 268892241e0bSTom Erickson * Try again in a second pass. 268992241e0bSTom Erickson */ 269092241e0bSTom Erickson err = nvlist_add_nvpair(retrynvl, pair); 269192241e0bSTom Erickson } 269292241e0bSTom Erickson } 269392241e0bSTom Erickson 26944445fffbSMatthew Ahrens if (err != 0) { 26954445fffbSMatthew Ahrens if (errlist != NULL) 26964445fffbSMatthew Ahrens fnvlist_add_int32(errlist, propname, err); 26974445fffbSMatthew Ahrens rv = err; 26984445fffbSMatthew Ahrens } 2699e9dbad6fSeschrock } 2700e9dbad6fSeschrock 270192241e0bSTom Erickson if (nvl != retrynvl && !nvlist_empty(retrynvl)) { 270292241e0bSTom Erickson nvl = retrynvl; 270392241e0bSTom Erickson goto retry; 270492241e0bSTom Erickson } 270592241e0bSTom Erickson 270692241e0bSTom Erickson if (!nvlist_empty(genericnvl) && 270792241e0bSTom Erickson dsl_props_set(dsname, source, genericnvl) != 0) { 270892241e0bSTom Erickson /* 270992241e0bSTom Erickson * If this fails, we still want to set as many properties as we 271092241e0bSTom Erickson * can, so try setting them individually. 271192241e0bSTom Erickson */ 271292241e0bSTom Erickson pair = NULL; 271392241e0bSTom Erickson while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) { 271492241e0bSTom Erickson const char *propname = nvpair_name(pair); 2715cfa69fd2STom Erickson int err = 0; 271692241e0bSTom Erickson 271792241e0bSTom Erickson propval = pair; 271892241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 271992241e0bSTom Erickson nvlist_t *attrs; 27204445fffbSMatthew Ahrens attrs = fnvpair_value_nvlist(pair); 27214445fffbSMatthew Ahrens propval = fnvlist_lookup_nvpair(attrs, 27224445fffbSMatthew Ahrens ZPROP_VALUE); 272392241e0bSTom Erickson } 272492241e0bSTom Erickson 272592241e0bSTom Erickson if (nvpair_type(propval) == DATA_TYPE_STRING) { 27264445fffbSMatthew Ahrens strval = fnvpair_value_string(propval); 27273b2aab18SMatthew Ahrens err = dsl_prop_set_string(dsname, propname, 27283b2aab18SMatthew Ahrens source, strval); 27296ccda740Sloli } else if (nvpair_type(propval) == DATA_TYPE_BOOLEAN) { 27306ccda740Sloli err = dsl_prop_inherit(dsname, propname, 27316ccda740Sloli source); 273292241e0bSTom Erickson } else { 27334445fffbSMatthew Ahrens intval = fnvpair_value_uint64(propval); 27343b2aab18SMatthew Ahrens err = dsl_prop_set_int(dsname, propname, source, 27353b2aab18SMatthew Ahrens intval); 273692241e0bSTom Erickson } 273792241e0bSTom Erickson 273892241e0bSTom Erickson if (err != 0) { 27394445fffbSMatthew Ahrens if (errlist != NULL) { 27404445fffbSMatthew Ahrens fnvlist_add_int32(errlist, propname, 27414445fffbSMatthew Ahrens err); 27424445fffbSMatthew Ahrens } 27434445fffbSMatthew Ahrens rv = err; 274492241e0bSTom Erickson } 274592241e0bSTom Erickson } 27465c0b6a79SRich Morris } 27475c0b6a79SRich Morris nvlist_free(genericnvl); 274892241e0bSTom Erickson nvlist_free(retrynvl); 274992241e0bSTom Erickson 275092241e0bSTom Erickson return (rv); 2751fa9e4066Sahrens } 2752fa9e4066Sahrens 2753ea2f5b9eSMatthew Ahrens /* 2754ea2f5b9eSMatthew Ahrens * Check that all the properties are valid user properties. 2755ea2f5b9eSMatthew Ahrens */ 2756ea2f5b9eSMatthew Ahrens static int 27574445fffbSMatthew Ahrens zfs_check_userprops(const char *fsname, nvlist_t *nvl) 2758ea2f5b9eSMatthew Ahrens { 275992241e0bSTom Erickson nvpair_t *pair = NULL; 2760ea2f5b9eSMatthew Ahrens int error = 0; 2761ea2f5b9eSMatthew Ahrens 276292241e0bSTom Erickson while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 276392241e0bSTom Erickson const char *propname = nvpair_name(pair); 2764ea2f5b9eSMatthew Ahrens 2765ea2f5b9eSMatthew Ahrens if (!zfs_prop_user(propname) || 276692241e0bSTom Erickson nvpair_type(pair) != DATA_TYPE_STRING) 2767be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2768ea2f5b9eSMatthew Ahrens 2769ea2f5b9eSMatthew Ahrens if (error = zfs_secpolicy_write_perms(fsname, 2770ea2f5b9eSMatthew Ahrens ZFS_DELEG_PERM_USERPROP, CRED())) 2771ea2f5b9eSMatthew Ahrens return (error); 2772ea2f5b9eSMatthew Ahrens 2773ea2f5b9eSMatthew Ahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 2774be6fd75aSMatthew Ahrens return (SET_ERROR(ENAMETOOLONG)); 2775ea2f5b9eSMatthew Ahrens 277678f17100SMatthew Ahrens if (strlen(fnvpair_value_string(pair)) >= ZAP_MAXVALUELEN) 2777ea2f5b9eSMatthew Ahrens return (E2BIG); 2778ea2f5b9eSMatthew Ahrens } 2779ea2f5b9eSMatthew Ahrens return (0); 2780ea2f5b9eSMatthew Ahrens } 2781ea2f5b9eSMatthew Ahrens 278292241e0bSTom Erickson static void 278392241e0bSTom Erickson props_skip(nvlist_t *props, nvlist_t *skipped, nvlist_t **newprops) 278492241e0bSTom Erickson { 278592241e0bSTom Erickson nvpair_t *pair; 278692241e0bSTom Erickson 278792241e0bSTom Erickson VERIFY(nvlist_alloc(newprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 278892241e0bSTom Erickson 278992241e0bSTom Erickson pair = NULL; 279092241e0bSTom Erickson while ((pair = nvlist_next_nvpair(props, pair)) != NULL) { 279192241e0bSTom Erickson if (nvlist_exists(skipped, nvpair_name(pair))) 279292241e0bSTom Erickson continue; 279392241e0bSTom Erickson 279492241e0bSTom Erickson VERIFY(nvlist_add_nvpair(*newprops, pair) == 0); 279592241e0bSTom Erickson } 279692241e0bSTom Erickson } 279792241e0bSTom Erickson 279892241e0bSTom Erickson static int 27993b2aab18SMatthew Ahrens clear_received_props(const char *dsname, nvlist_t *props, 280092241e0bSTom Erickson nvlist_t *skipped) 280192241e0bSTom Erickson { 280292241e0bSTom Erickson int err = 0; 280392241e0bSTom Erickson nvlist_t *cleared_props = NULL; 280492241e0bSTom Erickson props_skip(props, skipped, &cleared_props); 280592241e0bSTom Erickson if (!nvlist_empty(cleared_props)) { 280692241e0bSTom Erickson /* 280792241e0bSTom Erickson * Acts on local properties until the dataset has received 280892241e0bSTom Erickson * properties at least once on or after SPA_VERSION_RECVD_PROPS. 280992241e0bSTom Erickson */ 281092241e0bSTom Erickson zprop_source_t flags = (ZPROP_SRC_NONE | 28113b2aab18SMatthew Ahrens (dsl_prop_get_hasrecvd(dsname) ? ZPROP_SRC_RECEIVED : 0)); 28123b2aab18SMatthew Ahrens err = zfs_set_prop_nvlist(dsname, flags, cleared_props, NULL); 281392241e0bSTom Erickson } 281492241e0bSTom Erickson nvlist_free(cleared_props); 281592241e0bSTom Erickson return (err); 281692241e0bSTom Erickson } 281792241e0bSTom Erickson 28183cb34c60Sahrens /* 28193cb34c60Sahrens * inputs: 28203cb34c60Sahrens * zc_name name of filesystem 28215c0b6a79SRich Morris * zc_value name of property to set 28223cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 282392241e0bSTom Erickson * zc_cookie received properties flag 28243cb34c60Sahrens * 282592241e0bSTom Erickson * outputs: 282692241e0bSTom Erickson * zc_nvlist_dst{_size} error for each unapplied received property 28273cb34c60Sahrens */ 2828fa9e4066Sahrens static int 2829e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 2830fa9e4066Sahrens { 2831e9dbad6fSeschrock nvlist_t *nvl; 283292241e0bSTom Erickson boolean_t received = zc->zc_cookie; 283392241e0bSTom Erickson zprop_source_t source = (received ? ZPROP_SRC_RECEIVED : 283492241e0bSTom Erickson ZPROP_SRC_LOCAL); 28354445fffbSMatthew Ahrens nvlist_t *errors; 2836e9dbad6fSeschrock int error; 2837e9dbad6fSeschrock 2838990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2839478ed9adSEric Taylor zc->zc_iflags, &nvl)) != 0) 2840e9dbad6fSeschrock return (error); 2841e9dbad6fSeschrock 284292241e0bSTom Erickson if (received) { 2843bb0ade09Sahrens nvlist_t *origprops; 2844bb0ade09Sahrens 28453b2aab18SMatthew Ahrens if (dsl_prop_get_received(zc->zc_name, &origprops) == 0) { 28463b2aab18SMatthew Ahrens (void) clear_received_props(zc->zc_name, 28473b2aab18SMatthew Ahrens origprops, nvl); 28483b2aab18SMatthew Ahrens nvlist_free(origprops); 2849bb0ade09Sahrens } 28503b2aab18SMatthew Ahrens 28513b2aab18SMatthew Ahrens error = dsl_prop_set_hasrecvd(zc->zc_name); 2852bb0ade09Sahrens } 2853bb0ade09Sahrens 28544445fffbSMatthew Ahrens errors = fnvlist_alloc(); 28553b2aab18SMatthew Ahrens if (error == 0) 28563b2aab18SMatthew Ahrens error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, errors); 285792241e0bSTom Erickson 2858dd328bf6SToomas Soome if (zc->zc_nvlist_dst != 0 && errors != NULL) { 285992241e0bSTom Erickson (void) put_nvlist(zc, errors); 286092241e0bSTom Erickson } 2861ecd6cf80Smarks 286292241e0bSTom Erickson nvlist_free(errors); 2863e9dbad6fSeschrock nvlist_free(nvl); 2864e9dbad6fSeschrock return (error); 2865fa9e4066Sahrens } 2866fa9e4066Sahrens 28673cb34c60Sahrens /* 28683cb34c60Sahrens * inputs: 28693cb34c60Sahrens * zc_name name of filesystem 28703cb34c60Sahrens * zc_value name of property to inherit 287192241e0bSTom Erickson * zc_cookie revert to received value if TRUE 28723cb34c60Sahrens * 28733cb34c60Sahrens * outputs: none 28743cb34c60Sahrens */ 2875e45ce728Sahrens static int 2876e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 2877e45ce728Sahrens { 287892241e0bSTom Erickson const char *propname = zc->zc_value; 287992241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 288092241e0bSTom Erickson boolean_t received = zc->zc_cookie; 288192241e0bSTom Erickson zprop_source_t source = (received 288292241e0bSTom Erickson ? ZPROP_SRC_NONE /* revert to received value, if any */ 288392241e0bSTom Erickson : ZPROP_SRC_INHERITED); /* explicitly inherit */ 288492241e0bSTom Erickson 288592241e0bSTom Erickson if (received) { 288692241e0bSTom Erickson nvlist_t *dummy; 288792241e0bSTom Erickson nvpair_t *pair; 288892241e0bSTom Erickson zprop_type_t type; 288992241e0bSTom Erickson int err; 289092241e0bSTom Erickson 289192241e0bSTom Erickson /* 289292241e0bSTom Erickson * zfs_prop_set_special() expects properties in the form of an 289392241e0bSTom Erickson * nvpair with type info. 289492241e0bSTom Erickson */ 289592241e0bSTom Erickson if (prop == ZPROP_INVAL) { 289692241e0bSTom Erickson if (!zfs_prop_user(propname)) 2897be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 289892241e0bSTom Erickson 289992241e0bSTom Erickson type = PROP_TYPE_STRING; 2900a79992aaSTom Erickson } else if (prop == ZFS_PROP_VOLSIZE || 2901a79992aaSTom Erickson prop == ZFS_PROP_VERSION) { 2902be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 290392241e0bSTom Erickson } else { 290492241e0bSTom Erickson type = zfs_prop_get_type(prop); 290592241e0bSTom Erickson } 290692241e0bSTom Erickson 290792241e0bSTom Erickson VERIFY(nvlist_alloc(&dummy, NV_UNIQUE_NAME, KM_SLEEP) == 0); 290892241e0bSTom Erickson 290992241e0bSTom Erickson switch (type) { 291092241e0bSTom Erickson case PROP_TYPE_STRING: 291192241e0bSTom Erickson VERIFY(0 == nvlist_add_string(dummy, propname, "")); 291292241e0bSTom Erickson break; 291392241e0bSTom Erickson case PROP_TYPE_NUMBER: 291492241e0bSTom Erickson case PROP_TYPE_INDEX: 291592241e0bSTom Erickson VERIFY(0 == nvlist_add_uint64(dummy, propname, 0)); 291692241e0bSTom Erickson break; 291792241e0bSTom Erickson default: 291892241e0bSTom Erickson nvlist_free(dummy); 2919be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 292092241e0bSTom Erickson } 292192241e0bSTom Erickson 292292241e0bSTom Erickson pair = nvlist_next_nvpair(dummy, NULL); 292392241e0bSTom Erickson err = zfs_prop_set_special(zc->zc_name, source, pair); 292492241e0bSTom Erickson nvlist_free(dummy); 292592241e0bSTom Erickson if (err != -1) 292692241e0bSTom Erickson return (err); /* special property already handled */ 292792241e0bSTom Erickson } else { 292892241e0bSTom Erickson /* 292992241e0bSTom Erickson * Only check this in the non-received case. We want to allow 293092241e0bSTom Erickson * 'inherit -S' to revert non-inheritable properties like quota 293192241e0bSTom Erickson * and reservation to the received or default values even though 293292241e0bSTom Erickson * they are not considered inheritable. 293392241e0bSTom Erickson */ 293492241e0bSTom Erickson if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 2935be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 293692241e0bSTom Erickson } 293792241e0bSTom Erickson 29384445fffbSMatthew Ahrens /* property name has been validated by zfs_secpolicy_inherit_prop() */ 29393b2aab18SMatthew Ahrens return (dsl_prop_inherit(zc->zc_name, zc->zc_value, source)); 2940e45ce728Sahrens } 2941e45ce728Sahrens 2942b1b8ab34Slling static int 294311a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 2944b1b8ab34Slling { 2945990b4856Slling nvlist_t *props; 2946b1b8ab34Slling spa_t *spa; 2947990b4856Slling int error; 294892241e0bSTom Erickson nvpair_t *pair; 2949b1b8ab34Slling 295092241e0bSTom Erickson if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 295192241e0bSTom Erickson zc->zc_iflags, &props)) 2952b1b8ab34Slling return (error); 2953b1b8ab34Slling 2954379c004dSEric Schrock /* 2955379c004dSEric Schrock * If the only property is the configfile, then just do a spa_lookup() 2956379c004dSEric Schrock * to handle the faulted case. 2957379c004dSEric Schrock */ 295892241e0bSTom Erickson pair = nvlist_next_nvpair(props, NULL); 295992241e0bSTom Erickson if (pair != NULL && strcmp(nvpair_name(pair), 2960379c004dSEric Schrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 296192241e0bSTom Erickson nvlist_next_nvpair(props, pair) == NULL) { 2962379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 2963379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) { 2964379c004dSEric Schrock spa_configfile_set(spa, props, B_FALSE); 29655cabbc6bSPrashanth Sreenivasa spa_write_cachefile(spa, B_FALSE, B_TRUE); 2966379c004dSEric Schrock } 2967379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 2968b693757aSEric Schrock if (spa != NULL) { 2969b693757aSEric Schrock nvlist_free(props); 2970379c004dSEric Schrock return (0); 2971b693757aSEric Schrock } 2972379c004dSEric Schrock } 2973379c004dSEric Schrock 2974b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2975990b4856Slling nvlist_free(props); 2976b1b8ab34Slling return (error); 2977b1b8ab34Slling } 2978b1b8ab34Slling 2979990b4856Slling error = spa_prop_set(spa, props); 2980b1b8ab34Slling 2981990b4856Slling nvlist_free(props); 2982b1b8ab34Slling spa_close(spa, FTAG); 2983b1b8ab34Slling 2984b1b8ab34Slling return (error); 2985b1b8ab34Slling } 2986b1b8ab34Slling 2987b1b8ab34Slling static int 298811a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 2989b1b8ab34Slling { 2990b1b8ab34Slling spa_t *spa; 2991b1b8ab34Slling int error; 2992b1b8ab34Slling nvlist_t *nvp = NULL; 2993b1b8ab34Slling 2994379c004dSEric Schrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2995379c004dSEric Schrock /* 2996379c004dSEric Schrock * If the pool is faulted, there may be properties we can still 2997379c004dSEric Schrock * get (such as altroot and cachefile), so attempt to get them 2998379c004dSEric Schrock * anyway. 2999379c004dSEric Schrock */ 3000379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 3001379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) 3002379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 3003379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 3004379c004dSEric Schrock } else { 3005379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 3006379c004dSEric Schrock spa_close(spa, FTAG); 3007379c004dSEric Schrock } 3008b1b8ab34Slling 3009dd328bf6SToomas Soome if (error == 0 && zc->zc_nvlist_dst != 0) 3010b1b8ab34Slling error = put_nvlist(zc, nvp); 3011b1b8ab34Slling else 3012be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 3013b1b8ab34Slling 3014379c004dSEric Schrock nvlist_free(nvp); 3015b1b8ab34Slling return (error); 3016b1b8ab34Slling } 3017b1b8ab34Slling 30183cb34c60Sahrens /* 30193cb34c60Sahrens * inputs: 30203cb34c60Sahrens * zc_name name of filesystem 30213cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 30223cb34c60Sahrens * zc_perm_action allow/unallow flag 30233cb34c60Sahrens * 30243cb34c60Sahrens * outputs: none 30253cb34c60Sahrens */ 3026ecd6cf80Smarks static int 3027ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 3028ecd6cf80Smarks { 3029ecd6cf80Smarks int error; 3030ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 3031ecd6cf80Smarks 3032990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3033478ed9adSEric Taylor zc->zc_iflags, &fsaclnv)) != 0) 3034ecd6cf80Smarks return (error); 3035ecd6cf80Smarks 3036ecd6cf80Smarks /* 3037ecd6cf80Smarks * Verify nvlist is constructed correctly 3038ecd6cf80Smarks */ 3039ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 3040ecd6cf80Smarks nvlist_free(fsaclnv); 3041be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3042ecd6cf80Smarks } 3043ecd6cf80Smarks 3044ecd6cf80Smarks /* 3045ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 3046ecd6cf80Smarks * that user is allowed to hand out each permission in 3047ecd6cf80Smarks * the nvlist(s) 3048ecd6cf80Smarks */ 3049ecd6cf80Smarks 305091ebeef5Sahrens error = secpolicy_zfs(CRED()); 30513b2aab18SMatthew Ahrens if (error != 0) { 305291ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 305391ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 305491ebeef5Sahrens fsaclnv, CRED()); 305591ebeef5Sahrens } else { 305691ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 305791ebeef5Sahrens fsaclnv, CRED()); 305891ebeef5Sahrens } 3059ecd6cf80Smarks } 3060ecd6cf80Smarks 3061ecd6cf80Smarks if (error == 0) 3062ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 3063ecd6cf80Smarks 3064ecd6cf80Smarks nvlist_free(fsaclnv); 3065ecd6cf80Smarks return (error); 3066ecd6cf80Smarks } 3067ecd6cf80Smarks 30683cb34c60Sahrens /* 30693cb34c60Sahrens * inputs: 30703cb34c60Sahrens * zc_name name of filesystem 30713cb34c60Sahrens * 30723cb34c60Sahrens * outputs: 30733cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 30743cb34c60Sahrens */ 3075ecd6cf80Smarks static int 3076ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 3077ecd6cf80Smarks { 3078ecd6cf80Smarks nvlist_t *nvp; 3079ecd6cf80Smarks int error; 3080ecd6cf80Smarks 3081ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 3082ecd6cf80Smarks error = put_nvlist(zc, nvp); 3083ecd6cf80Smarks nvlist_free(nvp); 3084ecd6cf80Smarks } 3085ecd6cf80Smarks 3086ecd6cf80Smarks return (error); 3087ecd6cf80Smarks } 3088ecd6cf80Smarks 3089ecd6cf80Smarks /* ARGSUSED */ 3090fa9e4066Sahrens static void 3091ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 3092fa9e4066Sahrens { 3093da6c28aaSamw zfs_creat_t *zct = arg; 3094da6c28aaSamw 3095de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 3096da6c28aaSamw } 3097da6c28aaSamw 3098de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 3099da6c28aaSamw 3100da6c28aaSamw /* 3101de8267e0Stimh * inputs: 31020a48a24eStimh * os parent objset pointer (NULL if root fs) 3103f7170741SWill Andrews * fuids_ok fuids allowed in this version of the spa? 3104f7170741SWill Andrews * sa_ok SAs allowed in this version of the spa? 3105f7170741SWill Andrews * createprops list of properties requested by creator 3106de8267e0Stimh * 3107de8267e0Stimh * outputs: 3108de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 31090a48a24eStimh * is_ci true if requested file system will be purely case-insensitive 3110da6c28aaSamw * 3111de8267e0Stimh * Determine the settings for utf8only, normalization and 3112de8267e0Stimh * casesensitivity. Specific values may have been requested by the 3113de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 3114de8267e0Stimh * the file system is of too early a vintage, a creator can not 3115de8267e0Stimh * request settings for these properties, even if the requested 3116de8267e0Stimh * setting is the default value. We don't actually want to create dsl 3117de8267e0Stimh * properties for these, so remove them from the source nvlist after 3118de8267e0Stimh * processing. 3119da6c28aaSamw */ 3120da6c28aaSamw static int 312114843421SMatthew Ahrens zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 31220a586ceaSMark Shellenbaum boolean_t fuids_ok, boolean_t sa_ok, nvlist_t *createprops, 31230a586ceaSMark Shellenbaum nvlist_t *zplprops, boolean_t *is_ci) 3124da6c28aaSamw { 3125de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 3126de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 3127de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 3128da6c28aaSamw 3129de8267e0Stimh ASSERT(zplprops != NULL); 3130da6c28aaSamw 3131b127fe3cSAndriy Gapon if (os != NULL && os->os_phys->os_type != DMU_OST_ZFS) 3132b127fe3cSAndriy Gapon return (SET_ERROR(EINVAL)); 3133b127fe3cSAndriy Gapon 3134de8267e0Stimh /* 3135de8267e0Stimh * Pull out creator prop choices, if any. 3136de8267e0Stimh */ 3137de8267e0Stimh if (createprops) { 31380a48a24eStimh (void) nvlist_lookup_uint64(createprops, 31390a48a24eStimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 3140de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 3141de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 3142de8267e0Stimh (void) nvlist_remove_all(createprops, 3143de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 3144de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 3145de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 3146de8267e0Stimh (void) nvlist_remove_all(createprops, 3147de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 3148de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 3149de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 3150de8267e0Stimh (void) nvlist_remove_all(createprops, 3151de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 3152de8267e0Stimh } 3153da6c28aaSamw 3154c2a93d44Stimh /* 31550a48a24eStimh * If the zpl version requested is whacky or the file system 31560a48a24eStimh * or pool is version is too "young" to support normalization 31570a48a24eStimh * and the creator tried to set a value for one of the props, 31580a48a24eStimh * error out. 3159c2a93d44Stimh */ 31600a48a24eStimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 31610a48a24eStimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 31620a586ceaSMark Shellenbaum (zplver >= ZPL_VERSION_SA && !sa_ok) || 31630a48a24eStimh (zplver < ZPL_VERSION_NORMALIZATION && 3164de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 31650a48a24eStimh sense != ZFS_PROP_UNDEFINED))) 3166be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 3167c2a93d44Stimh 3168de8267e0Stimh /* 3169de8267e0Stimh * Put the version in the zplprops 3170de8267e0Stimh */ 3171de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3172de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 3173da6c28aaSamw 3174de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 3175de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 3176de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3177de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 3178da6c28aaSamw 3179c2a93d44Stimh /* 3180de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 3181c2a93d44Stimh */ 3182de8267e0Stimh if (norm) 3183de8267e0Stimh u8 = 1; 3184de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 3185de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 3186de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3187de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 3188de8267e0Stimh 3189de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 3190de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 3191de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3192de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 3193c2a93d44Stimh 3194ab04eb8eStimh if (is_ci) 3195ab04eb8eStimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 3196ab04eb8eStimh 3197da6c28aaSamw return (0); 3198fa9e4066Sahrens } 3199fa9e4066Sahrens 32000a48a24eStimh static int 32010a48a24eStimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 32020a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 32030a48a24eStimh { 32040a586ceaSMark Shellenbaum boolean_t fuids_ok, sa_ok; 32050a48a24eStimh uint64_t zplver = ZPL_VERSION; 32060a48a24eStimh objset_t *os = NULL; 32079adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 32080a48a24eStimh char *cp; 32090a586ceaSMark Shellenbaum spa_t *spa; 32100a586ceaSMark Shellenbaum uint64_t spa_vers; 32110a48a24eStimh int error; 32120a48a24eStimh 32130a48a24eStimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 32140a48a24eStimh cp = strrchr(parentname, '/'); 32150a48a24eStimh ASSERT(cp != NULL); 32160a48a24eStimh cp[0] = '\0'; 32170a48a24eStimh 32180a586ceaSMark Shellenbaum if ((error = spa_open(dataset, &spa, FTAG)) != 0) 32190a586ceaSMark Shellenbaum return (error); 32200a586ceaSMark Shellenbaum 32210a586ceaSMark Shellenbaum spa_vers = spa_version(spa); 32220a586ceaSMark Shellenbaum spa_close(spa, FTAG); 32230a586ceaSMark Shellenbaum 32240a586ceaSMark Shellenbaum zplver = zfs_zpl_version_map(spa_vers); 32250a586ceaSMark Shellenbaum fuids_ok = (zplver >= ZPL_VERSION_FUID); 32260a586ceaSMark Shellenbaum sa_ok = (zplver >= ZPL_VERSION_SA); 32270a48a24eStimh 32280a48a24eStimh /* 32290a48a24eStimh * Open parent object set so we can inherit zplprop values. 32300a48a24eStimh */ 3231503ad85cSMatthew Ahrens if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0) 32320a48a24eStimh return (error); 32330a48a24eStimh 32340a586ceaSMark Shellenbaum error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, sa_ok, createprops, 32350a48a24eStimh zplprops, is_ci); 3236503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 32370a48a24eStimh return (error); 32380a48a24eStimh } 32390a48a24eStimh 32400a48a24eStimh static int 32410a48a24eStimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 32420a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 32430a48a24eStimh { 32440a586ceaSMark Shellenbaum boolean_t fuids_ok; 32450a586ceaSMark Shellenbaum boolean_t sa_ok; 32460a48a24eStimh uint64_t zplver = ZPL_VERSION; 32470a48a24eStimh int error; 32480a48a24eStimh 32490a586ceaSMark Shellenbaum zplver = zfs_zpl_version_map(spa_vers); 32500a586ceaSMark Shellenbaum fuids_ok = (zplver >= ZPL_VERSION_FUID); 32510a586ceaSMark Shellenbaum sa_ok = (zplver >= ZPL_VERSION_SA); 32520a48a24eStimh 32530a586ceaSMark Shellenbaum error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, sa_ok, 32540a586ceaSMark Shellenbaum createprops, zplprops, is_ci); 32550a48a24eStimh return (error); 32560a48a24eStimh } 32570a48a24eStimh 32583cb34c60Sahrens /* 32594445fffbSMatthew Ahrens * innvl: { 32604445fffbSMatthew Ahrens * "type" -> dmu_objset_type_t (int32) 32614445fffbSMatthew Ahrens * (optional) "props" -> { prop -> value } 3262eb633035STom Caputi * (optional) "hidden_args" -> { "wkeydata" -> value } 3263eb633035STom Caputi * raw uint8_t array of encryption wrapping key data (32 bytes) 32644445fffbSMatthew Ahrens * } 32653cb34c60Sahrens * 32664445fffbSMatthew Ahrens * outnvl: propname -> error code (int32) 32673cb34c60Sahrens */ 3268fa9e4066Sahrens static int 32694445fffbSMatthew Ahrens zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 3270fa9e4066Sahrens { 3271fa9e4066Sahrens int error = 0; 32724445fffbSMatthew Ahrens zfs_creat_t zct = { 0 }; 3273ecd6cf80Smarks nvlist_t *nvprops = NULL; 3274eb633035STom Caputi nvlist_t *hidden_args = NULL; 3275ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 32764445fffbSMatthew Ahrens int32_t type32; 32774445fffbSMatthew Ahrens dmu_objset_type_t type; 32784445fffbSMatthew Ahrens boolean_t is_insensitive = B_FALSE; 3279eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 3280fa9e4066Sahrens 32814445fffbSMatthew Ahrens if (nvlist_lookup_int32(innvl, "type", &type32) != 0) 3282be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 32834445fffbSMatthew Ahrens type = type32; 32844445fffbSMatthew Ahrens (void) nvlist_lookup_nvlist(innvl, "props", &nvprops); 3285eb633035STom Caputi (void) nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args); 3286fa9e4066Sahrens 32874445fffbSMatthew Ahrens switch (type) { 3288fa9e4066Sahrens case DMU_OST_ZFS: 3289fa9e4066Sahrens cbfunc = zfs_create_cb; 3290fa9e4066Sahrens break; 3291fa9e4066Sahrens 3292fa9e4066Sahrens case DMU_OST_ZVOL: 3293fa9e4066Sahrens cbfunc = zvol_create_cb; 3294fa9e4066Sahrens break; 3295fa9e4066Sahrens 3296fa9e4066Sahrens default: 32971d452cf5Sahrens cbfunc = NULL; 3298e7cbe64fSgw break; 3299fa9e4066Sahrens } 33004445fffbSMatthew Ahrens if (strchr(fsname, '@') || 33014445fffbSMatthew Ahrens strchr(fsname, '%')) 3302be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3303fa9e4066Sahrens 3304da6c28aaSamw zct.zct_props = nvprops; 3305da6c28aaSamw 33064445fffbSMatthew Ahrens if (cbfunc == NULL) 3307be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 33084445fffbSMatthew Ahrens 33094445fffbSMatthew Ahrens if (type == DMU_OST_ZVOL) { 33104445fffbSMatthew Ahrens uint64_t volsize, volblocksize; 33114445fffbSMatthew Ahrens 33124445fffbSMatthew Ahrens if (nvprops == NULL) 3313be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 33144445fffbSMatthew Ahrens if (nvlist_lookup_uint64(nvprops, 33154445fffbSMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) != 0) 3316be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3317fa9e4066Sahrens 33184445fffbSMatthew Ahrens if ((error = nvlist_lookup_uint64(nvprops, 33194445fffbSMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 33204445fffbSMatthew Ahrens &volblocksize)) != 0 && error != ENOENT) 3321be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 33224445fffbSMatthew Ahrens 33234445fffbSMatthew Ahrens if (error != 0) 33244445fffbSMatthew Ahrens volblocksize = zfs_prop_default_numeric( 33254445fffbSMatthew Ahrens ZFS_PROP_VOLBLOCKSIZE); 33264445fffbSMatthew Ahrens 33274445fffbSMatthew Ahrens if ((error = zvol_check_volblocksize( 33284445fffbSMatthew Ahrens volblocksize)) != 0 || 33294445fffbSMatthew Ahrens (error = zvol_check_volsize(volsize, 33304445fffbSMatthew Ahrens volblocksize)) != 0) 3331fa9e4066Sahrens return (error); 33324445fffbSMatthew Ahrens } else if (type == DMU_OST_ZFS) { 33334445fffbSMatthew Ahrens int error; 3334ab04eb8eStimh 33354445fffbSMatthew Ahrens /* 33364445fffbSMatthew Ahrens * We have to have normalization and 33374445fffbSMatthew Ahrens * case-folding flags correct when we do the 33384445fffbSMatthew Ahrens * file system creation, so go figure them out 33394445fffbSMatthew Ahrens * now. 33404445fffbSMatthew Ahrens */ 33414445fffbSMatthew Ahrens VERIFY(nvlist_alloc(&zct.zct_zplprops, 33424445fffbSMatthew Ahrens NV_UNIQUE_NAME, KM_SLEEP) == 0); 33434445fffbSMatthew Ahrens error = zfs_fill_zplprops(fsname, nvprops, 33444445fffbSMatthew Ahrens zct.zct_zplprops, &is_insensitive); 33454445fffbSMatthew Ahrens if (error != 0) { 33464445fffbSMatthew Ahrens nvlist_free(zct.zct_zplprops); 3347da6c28aaSamw return (error); 3348da6c28aaSamw } 33494445fffbSMatthew Ahrens } 3350ab04eb8eStimh 3351eb633035STom Caputi error = dsl_crypto_params_create_nvlist(DCP_CMD_NONE, nvprops, 3352eb633035STom Caputi hidden_args, &dcp); 3353eb633035STom Caputi if (error != 0) { 3354eb633035STom Caputi nvlist_free(zct.zct_zplprops); 3355eb633035STom Caputi return (error); 3356eb633035STom Caputi } 3357eb633035STom Caputi 33584445fffbSMatthew Ahrens error = dmu_objset_create(fsname, type, 3359eb633035STom Caputi is_insensitive ? DS_FLAG_CI_DATASET : 0, dcp, cbfunc, &zct); 3360eb633035STom Caputi 33614445fffbSMatthew Ahrens nvlist_free(zct.zct_zplprops); 3362eb633035STom Caputi dsl_crypto_params_free(dcp, !!error); 33635c5460e9Seschrock 33644445fffbSMatthew Ahrens /* 33654445fffbSMatthew Ahrens * It would be nice to do this atomically. 33664445fffbSMatthew Ahrens */ 33674445fffbSMatthew Ahrens if (error == 0) { 33684445fffbSMatthew Ahrens error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, 33694445fffbSMatthew Ahrens nvprops, outnvl); 33704445fffbSMatthew Ahrens if (error != 0) 33713b2aab18SMatthew Ahrens (void) dsl_destroy_head(fsname); 33724445fffbSMatthew Ahrens } 33734445fffbSMatthew Ahrens return (error); 33744445fffbSMatthew Ahrens } 3375e9dbad6fSeschrock 33764445fffbSMatthew Ahrens /* 33774445fffbSMatthew Ahrens * innvl: { 33784445fffbSMatthew Ahrens * "origin" -> name of origin snapshot 33794445fffbSMatthew Ahrens * (optional) "props" -> { prop -> value } 3380eb633035STom Caputi * (optional) "hidden_args" -> { "wkeydata" -> value } 3381eb633035STom Caputi * raw uint8_t array of encryption wrapping key data (32 bytes) 33824445fffbSMatthew Ahrens * } 33834445fffbSMatthew Ahrens * 33844445fffbSMatthew Ahrens * outnvl: propname -> error code (int32) 33854445fffbSMatthew Ahrens */ 33864445fffbSMatthew Ahrens static int 33874445fffbSMatthew Ahrens zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 33884445fffbSMatthew Ahrens { 33894445fffbSMatthew Ahrens int error = 0; 33904445fffbSMatthew Ahrens nvlist_t *nvprops = NULL; 33914445fffbSMatthew Ahrens char *origin_name; 3392e9dbad6fSeschrock 33934445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "origin", &origin_name) != 0) 3394be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 33954445fffbSMatthew Ahrens (void) nvlist_lookup_nvlist(innvl, "props", &nvprops); 3396e9dbad6fSeschrock 33974445fffbSMatthew Ahrens if (strchr(fsname, '@') || 33984445fffbSMatthew Ahrens strchr(fsname, '%')) 3399be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3400e9dbad6fSeschrock 34014445fffbSMatthew Ahrens if (dataset_namecheck(origin_name, NULL, NULL) != 0) 3402be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3403eb633035STom Caputi 34043b2aab18SMatthew Ahrens error = dmu_objset_clone(fsname, origin_name); 3405e9dbad6fSeschrock 3406e9dbad6fSeschrock /* 3407e9dbad6fSeschrock * It would be nice to do this atomically. 3408e9dbad6fSeschrock */ 3409e9dbad6fSeschrock if (error == 0) { 34104445fffbSMatthew Ahrens error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, 34114445fffbSMatthew Ahrens nvprops, outnvl); 341292241e0bSTom Erickson if (error != 0) 34133b2aab18SMatthew Ahrens (void) dsl_destroy_head(fsname); 3414e9dbad6fSeschrock } 3415fa9e4066Sahrens return (error); 3416fa9e4066Sahrens } 3417fa9e4066Sahrens 34185cabbc6bSPrashanth Sreenivasa /* ARGSUSED */ 34195cabbc6bSPrashanth Sreenivasa static int 34205cabbc6bSPrashanth Sreenivasa zfs_ioc_remap(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 34215cabbc6bSPrashanth Sreenivasa { 34225cabbc6bSPrashanth Sreenivasa if (strchr(fsname, '@') || 34235cabbc6bSPrashanth Sreenivasa strchr(fsname, '%')) 34245cabbc6bSPrashanth Sreenivasa return (SET_ERROR(EINVAL)); 34255cabbc6bSPrashanth Sreenivasa 34265cabbc6bSPrashanth Sreenivasa return (dmu_objset_remap_indirects(fsname)); 34275cabbc6bSPrashanth Sreenivasa } 34285cabbc6bSPrashanth Sreenivasa 34293cb34c60Sahrens /* 34304445fffbSMatthew Ahrens * innvl: { 34314445fffbSMatthew Ahrens * "snaps" -> { snapshot1, snapshot2 } 34324445fffbSMatthew Ahrens * (optional) "props" -> { prop -> value (string) } 34334445fffbSMatthew Ahrens * } 34344445fffbSMatthew Ahrens * 34354445fffbSMatthew Ahrens * outnvl: snapshot -> error code (int32) 34363cb34c60Sahrens */ 3437fa9e4066Sahrens static int 34384445fffbSMatthew Ahrens zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 3439fa9e4066Sahrens { 34404445fffbSMatthew Ahrens nvlist_t *snaps; 34414445fffbSMatthew Ahrens nvlist_t *props = NULL; 34424445fffbSMatthew Ahrens int error, poollen; 34434445fffbSMatthew Ahrens nvpair_t *pair; 3444bb0ade09Sahrens 34454445fffbSMatthew Ahrens (void) nvlist_lookup_nvlist(innvl, "props", &props); 34464445fffbSMatthew Ahrens if ((error = zfs_check_userprops(poolname, props)) != 0) 34474445fffbSMatthew Ahrens return (error); 34484445fffbSMatthew Ahrens 34494445fffbSMatthew Ahrens if (!nvlist_empty(props) && 34504445fffbSMatthew Ahrens zfs_earlier_version(poolname, SPA_VERSION_SNAP_PROPS)) 3451be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 34524445fffbSMatthew Ahrens 34534445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 3454be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 34554445fffbSMatthew Ahrens poollen = strlen(poolname); 34564445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 34574445fffbSMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 34584445fffbSMatthew Ahrens const char *name = nvpair_name(pair); 34594445fffbSMatthew Ahrens const char *cp = strchr(name, '@'); 3460bb0ade09Sahrens 34614445fffbSMatthew Ahrens /* 34624445fffbSMatthew Ahrens * The snap name must contain an @, and the part after it must 34634445fffbSMatthew Ahrens * contain only valid characters. 34644445fffbSMatthew Ahrens */ 346578f17100SMatthew Ahrens if (cp == NULL || 346678f17100SMatthew Ahrens zfs_component_namecheck(cp + 1, NULL, NULL) != 0) 3467be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3468bb0ade09Sahrens 34694445fffbSMatthew Ahrens /* 34704445fffbSMatthew Ahrens * The snap must be in the specified pool. 34714445fffbSMatthew Ahrens */ 34724445fffbSMatthew Ahrens if (strncmp(name, poolname, poollen) != 0 || 34734445fffbSMatthew Ahrens (name[poollen] != '/' && name[poollen] != '@')) 3474be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 34754445fffbSMatthew Ahrens 34764445fffbSMatthew Ahrens /* This must be the only snap of this fs. */ 34774445fffbSMatthew Ahrens for (nvpair_t *pair2 = nvlist_next_nvpair(snaps, pair); 34784445fffbSMatthew Ahrens pair2 != NULL; pair2 = nvlist_next_nvpair(snaps, pair2)) { 34794445fffbSMatthew Ahrens if (strncmp(name, nvpair_name(pair2), cp - name + 1) 34804445fffbSMatthew Ahrens == 0) { 3481be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 34824445fffbSMatthew Ahrens } 34834445fffbSMatthew Ahrens } 34844445fffbSMatthew Ahrens } 3485bb0ade09Sahrens 34863b2aab18SMatthew Ahrens error = dsl_dataset_snapshot(snaps, props, outnvl); 34874445fffbSMatthew Ahrens return (error); 34884445fffbSMatthew Ahrens } 34894445fffbSMatthew Ahrens 34904445fffbSMatthew Ahrens /* 34914445fffbSMatthew Ahrens * innvl: "message" -> string 34924445fffbSMatthew Ahrens */ 34934445fffbSMatthew Ahrens /* ARGSUSED */ 34944445fffbSMatthew Ahrens static int 34954445fffbSMatthew Ahrens zfs_ioc_log_history(const char *unused, nvlist_t *innvl, nvlist_t *outnvl) 34964445fffbSMatthew Ahrens { 34974445fffbSMatthew Ahrens char *message; 34984445fffbSMatthew Ahrens spa_t *spa; 34994445fffbSMatthew Ahrens int error; 35004445fffbSMatthew Ahrens char *poolname; 35014445fffbSMatthew Ahrens 35024445fffbSMatthew Ahrens /* 35034445fffbSMatthew Ahrens * The poolname in the ioctl is not set, we get it from the TSD, 35044445fffbSMatthew Ahrens * which was set at the end of the last successful ioctl that allows 35054445fffbSMatthew Ahrens * logging. The secpolicy func already checked that it is set. 35064445fffbSMatthew Ahrens * Only one log ioctl is allowed after each successful ioctl, so 35074445fffbSMatthew Ahrens * we clear the TSD here. 35084445fffbSMatthew Ahrens */ 35094445fffbSMatthew Ahrens poolname = tsd_get(zfs_allow_log_key); 35104445fffbSMatthew Ahrens (void) tsd_set(zfs_allow_log_key, NULL); 35114445fffbSMatthew Ahrens error = spa_open(poolname, &spa, FTAG); 35124445fffbSMatthew Ahrens strfree(poolname); 35134445fffbSMatthew Ahrens if (error != 0) 35144445fffbSMatthew Ahrens return (error); 35154445fffbSMatthew Ahrens 35164445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "message", &message) != 0) { 35174445fffbSMatthew Ahrens spa_close(spa, FTAG); 3518be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3519bb0ade09Sahrens } 3520ea2f5b9eSMatthew Ahrens 35214445fffbSMatthew Ahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 35224445fffbSMatthew Ahrens spa_close(spa, FTAG); 3523be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 35244445fffbSMatthew Ahrens } 3525ea2f5b9eSMatthew Ahrens 35264445fffbSMatthew Ahrens error = spa_history_log(spa, message); 35274445fffbSMatthew Ahrens spa_close(spa, FTAG); 3528bb0ade09Sahrens return (error); 35291d452cf5Sahrens } 3530fa9e4066Sahrens 35313b2aab18SMatthew Ahrens /* 35323b2aab18SMatthew Ahrens * The dp_config_rwlock must not be held when calling this, because the 35333b2aab18SMatthew Ahrens * unmount may need to write out data. 35343b2aab18SMatthew Ahrens * 35353b2aab18SMatthew Ahrens * This function is best-effort. Callers must deal gracefully if it 35363b2aab18SMatthew Ahrens * remains mounted (or is remounted after this call). 3537fc7a6e3fSWill Andrews * 3538fc7a6e3fSWill Andrews * Returns 0 if the argument is not a snapshot, or it is not currently a 3539fc7a6e3fSWill Andrews * filesystem, or we were able to unmount it. Returns error code otherwise. 35403b2aab18SMatthew Ahrens */ 3541ed992b0aSSerapheim Dimitropoulos void 35423b2aab18SMatthew Ahrens zfs_unmount_snap(const char *snapname) 35431d452cf5Sahrens { 3544ed992b0aSSerapheim Dimitropoulos vfs_t *vfsp = NULL; 3545ed992b0aSSerapheim Dimitropoulos zfsvfs_t *zfsvfs = NULL; 35461d452cf5Sahrens 35473b2aab18SMatthew Ahrens if (strchr(snapname, '@') == NULL) 3548ed992b0aSSerapheim Dimitropoulos return; 35491d452cf5Sahrens 3550ed992b0aSSerapheim Dimitropoulos int err = getzfsvfs(snapname, &zfsvfs); 3551ed992b0aSSerapheim Dimitropoulos if (err != 0) { 3552ed992b0aSSerapheim Dimitropoulos ASSERT3P(zfsvfs, ==, NULL); 3553ed992b0aSSerapheim Dimitropoulos return; 3554ed992b0aSSerapheim Dimitropoulos } 3555ed992b0aSSerapheim Dimitropoulos vfsp = zfsvfs->z_vfs; 35563b2aab18SMatthew Ahrens 35573b2aab18SMatthew Ahrens ASSERT(!dsl_pool_config_held(dmu_objset_pool(zfsvfs->z_os))); 35581d452cf5Sahrens 3559fc7a6e3fSWill Andrews err = vn_vfswlock(vfsp->vfs_vnodecovered); 35604445fffbSMatthew Ahrens VFS_RELE(vfsp); 3561fc7a6e3fSWill Andrews if (err != 0) 3562ed992b0aSSerapheim Dimitropoulos return; 35634445fffbSMatthew Ahrens 35644445fffbSMatthew Ahrens /* 35654445fffbSMatthew Ahrens * Always force the unmount for snapshots. 35664445fffbSMatthew Ahrens */ 35673b2aab18SMatthew Ahrens (void) dounmount(vfsp, MS_FORCE, kcred); 35683b2aab18SMatthew Ahrens } 35693b2aab18SMatthew Ahrens 35703b2aab18SMatthew Ahrens /* ARGSUSED */ 35713b2aab18SMatthew Ahrens static int 35723b2aab18SMatthew Ahrens zfs_unmount_snap_cb(const char *snapname, void *arg) 35733b2aab18SMatthew Ahrens { 3574ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(snapname); 3575ed992b0aSSerapheim Dimitropoulos return (0); 35763b2aab18SMatthew Ahrens } 35773b2aab18SMatthew Ahrens 35783b2aab18SMatthew Ahrens /* 35793b2aab18SMatthew Ahrens * When a clone is destroyed, its origin may also need to be destroyed, 35803b2aab18SMatthew Ahrens * in which case it must be unmounted. This routine will do that unmount 35813b2aab18SMatthew Ahrens * if necessary. 35823b2aab18SMatthew Ahrens */ 35833b2aab18SMatthew Ahrens void 35843b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(const char *fsname) 35853b2aab18SMatthew Ahrens { 35863b2aab18SMatthew Ahrens int error; 35873b2aab18SMatthew Ahrens objset_t *os; 35883b2aab18SMatthew Ahrens dsl_dataset_t *ds; 35893b2aab18SMatthew Ahrens 35903b2aab18SMatthew Ahrens error = dmu_objset_hold(fsname, FTAG, &os); 35913b2aab18SMatthew Ahrens if (error != 0) 35923b2aab18SMatthew Ahrens return; 35933b2aab18SMatthew Ahrens ds = dmu_objset_ds(os); 35943b2aab18SMatthew Ahrens if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) { 35959adfa60dSMatthew Ahrens char originname[ZFS_MAX_DATASET_NAME_LEN]; 35963b2aab18SMatthew Ahrens dsl_dataset_name(ds->ds_prev, originname); 35973b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 3598ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(originname); 35993b2aab18SMatthew Ahrens } else { 36003b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 36013b2aab18SMatthew Ahrens } 36021d452cf5Sahrens } 36031d452cf5Sahrens 36043cb34c60Sahrens /* 36054445fffbSMatthew Ahrens * innvl: { 36064445fffbSMatthew Ahrens * "snaps" -> { snapshot1, snapshot2 } 36074445fffbSMatthew Ahrens * (optional boolean) "defer" 36084445fffbSMatthew Ahrens * } 36094445fffbSMatthew Ahrens * 36104445fffbSMatthew Ahrens * outnvl: snapshot -> error code (int32) 36113cb34c60Sahrens * 36123cb34c60Sahrens */ 361378f17100SMatthew Ahrens /* ARGSUSED */ 36141d452cf5Sahrens static int 36154445fffbSMatthew Ahrens zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 36161d452cf5Sahrens { 36174445fffbSMatthew Ahrens nvlist_t *snaps; 361819b94df9SMatthew Ahrens nvpair_t *pair; 36194445fffbSMatthew Ahrens boolean_t defer; 36201d452cf5Sahrens 36214445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 3622be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 36234445fffbSMatthew Ahrens defer = nvlist_exists(innvl, "defer"); 362419b94df9SMatthew Ahrens 36254445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 36264445fffbSMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 3627ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(nvpair_name(pair)); 362878f17100SMatthew Ahrens } 362978f17100SMatthew Ahrens 363078f17100SMatthew Ahrens return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl)); 363178f17100SMatthew Ahrens } 363278f17100SMatthew Ahrens 363378f17100SMatthew Ahrens /* 363478f17100SMatthew Ahrens * Create bookmarks. Bookmark names are of the form <fs>#<bmark>. 363578f17100SMatthew Ahrens * All bookmarks must be in the same pool. 363678f17100SMatthew Ahrens * 363778f17100SMatthew Ahrens * innvl: { 363878f17100SMatthew Ahrens * bookmark1 -> snapshot1, bookmark2 -> snapshot2 363978f17100SMatthew Ahrens * } 364078f17100SMatthew Ahrens * 364178f17100SMatthew Ahrens * outnvl: bookmark -> error code (int32) 364278f17100SMatthew Ahrens * 364378f17100SMatthew Ahrens */ 364478f17100SMatthew Ahrens /* ARGSUSED */ 364578f17100SMatthew Ahrens static int 364678f17100SMatthew Ahrens zfs_ioc_bookmark(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 364778f17100SMatthew Ahrens { 364878f17100SMatthew Ahrens for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL); 364978f17100SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) { 365078f17100SMatthew Ahrens char *snap_name; 365178f17100SMatthew Ahrens 365278f17100SMatthew Ahrens /* 365378f17100SMatthew Ahrens * Verify the snapshot argument. 365478f17100SMatthew Ahrens */ 365578f17100SMatthew Ahrens if (nvpair_value_string(pair, &snap_name) != 0) 365678f17100SMatthew Ahrens return (SET_ERROR(EINVAL)); 365778f17100SMatthew Ahrens 365878f17100SMatthew Ahrens 365978f17100SMatthew Ahrens /* Verify that the keys (bookmarks) are unique */ 366078f17100SMatthew Ahrens for (nvpair_t *pair2 = nvlist_next_nvpair(innvl, pair); 366178f17100SMatthew Ahrens pair2 != NULL; pair2 = nvlist_next_nvpair(innvl, pair2)) { 366278f17100SMatthew Ahrens if (strcmp(nvpair_name(pair), nvpair_name(pair2)) == 0) 366378f17100SMatthew Ahrens return (SET_ERROR(EINVAL)); 366478f17100SMatthew Ahrens } 366578f17100SMatthew Ahrens } 366678f17100SMatthew Ahrens 366778f17100SMatthew Ahrens return (dsl_bookmark_create(innvl, outnvl)); 366878f17100SMatthew Ahrens } 366978f17100SMatthew Ahrens 367078f17100SMatthew Ahrens /* 367178f17100SMatthew Ahrens * innvl: { 367278f17100SMatthew Ahrens * property 1, property 2, ... 367378f17100SMatthew Ahrens * } 367478f17100SMatthew Ahrens * 367578f17100SMatthew Ahrens * outnvl: { 367678f17100SMatthew Ahrens * bookmark name 1 -> { property 1, property 2, ... }, 367778f17100SMatthew Ahrens * bookmark name 2 -> { property 1, property 2, ... } 367878f17100SMatthew Ahrens * } 367978f17100SMatthew Ahrens * 368078f17100SMatthew Ahrens */ 368178f17100SMatthew Ahrens static int 368278f17100SMatthew Ahrens zfs_ioc_get_bookmarks(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 368378f17100SMatthew Ahrens { 368478f17100SMatthew Ahrens return (dsl_get_bookmarks(fsname, innvl, outnvl)); 368578f17100SMatthew Ahrens } 368678f17100SMatthew Ahrens 368778f17100SMatthew Ahrens /* 368878f17100SMatthew Ahrens * innvl: { 368978f17100SMatthew Ahrens * bookmark name 1, bookmark name 2 369078f17100SMatthew Ahrens * } 369178f17100SMatthew Ahrens * 369278f17100SMatthew Ahrens * outnvl: bookmark -> error code (int32) 369378f17100SMatthew Ahrens * 369478f17100SMatthew Ahrens */ 369578f17100SMatthew Ahrens static int 369678f17100SMatthew Ahrens zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl, 369778f17100SMatthew Ahrens nvlist_t *outnvl) 369878f17100SMatthew Ahrens { 369978f17100SMatthew Ahrens int error, poollen; 370078f17100SMatthew Ahrens 370178f17100SMatthew Ahrens poollen = strlen(poolname); 370278f17100SMatthew Ahrens for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL); 370378f17100SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) { 370419b94df9SMatthew Ahrens const char *name = nvpair_name(pair); 370578f17100SMatthew Ahrens const char *cp = strchr(name, '#'); 37064445fffbSMatthew Ahrens 370719b94df9SMatthew Ahrens /* 370878f17100SMatthew Ahrens * The bookmark name must contain an #, and the part after it 370978f17100SMatthew Ahrens * must contain only valid characters. 371078f17100SMatthew Ahrens */ 371178f17100SMatthew Ahrens if (cp == NULL || 371278f17100SMatthew Ahrens zfs_component_namecheck(cp + 1, NULL, NULL) != 0) 371378f17100SMatthew Ahrens return (SET_ERROR(EINVAL)); 371478f17100SMatthew Ahrens 371578f17100SMatthew Ahrens /* 371678f17100SMatthew Ahrens * The bookmark must be in the specified pool. 371719b94df9SMatthew Ahrens */ 37184445fffbSMatthew Ahrens if (strncmp(name, poolname, poollen) != 0 || 371978f17100SMatthew Ahrens (name[poollen] != '/' && name[poollen] != '#')) 3720be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 372119b94df9SMatthew Ahrens } 372219b94df9SMatthew Ahrens 372378f17100SMatthew Ahrens error = dsl_bookmark_destroy(innvl, outnvl); 372478f17100SMatthew Ahrens return (error); 37251d452cf5Sahrens } 37261d452cf5Sahrens 3727dfc11533SChris Williamson static int 3728dfc11533SChris Williamson zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl, 3729dfc11533SChris Williamson nvlist_t *outnvl) 3730dfc11533SChris Williamson { 3731dfc11533SChris Williamson char *program; 3732dfc11533SChris Williamson uint64_t instrlimit, memlimit; 3733a3b28680SSerapheim Dimitropoulos boolean_t sync_flag; 3734dfc11533SChris Williamson nvpair_t *nvarg = NULL; 3735dfc11533SChris Williamson 3736dfc11533SChris Williamson if (0 != nvlist_lookup_string(innvl, ZCP_ARG_PROGRAM, &program)) { 3737dfc11533SChris Williamson return (EINVAL); 3738dfc11533SChris Williamson } 3739a3b28680SSerapheim Dimitropoulos if (0 != nvlist_lookup_boolean_value(innvl, ZCP_ARG_SYNC, &sync_flag)) { 3740a3b28680SSerapheim Dimitropoulos sync_flag = B_TRUE; 3741a3b28680SSerapheim Dimitropoulos } 3742dfc11533SChris Williamson if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_INSTRLIMIT, &instrlimit)) { 3743dfc11533SChris Williamson instrlimit = ZCP_DEFAULT_INSTRLIMIT; 3744dfc11533SChris Williamson } 3745dfc11533SChris Williamson if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_MEMLIMIT, &memlimit)) { 3746dfc11533SChris Williamson memlimit = ZCP_DEFAULT_MEMLIMIT; 3747dfc11533SChris Williamson } 3748dfc11533SChris Williamson if (0 != nvlist_lookup_nvpair(innvl, ZCP_ARG_ARGLIST, &nvarg)) { 3749dfc11533SChris Williamson return (EINVAL); 3750dfc11533SChris Williamson } 3751dfc11533SChris Williamson 3752dfc11533SChris Williamson if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit) 3753dfc11533SChris Williamson return (EINVAL); 37542840dce1SChris Williamson if (memlimit == 0 || memlimit > zfs_lua_max_memlimit) 3755dfc11533SChris Williamson return (EINVAL); 3756dfc11533SChris Williamson 3757a3b28680SSerapheim Dimitropoulos return (zcp_eval(poolname, program, sync_flag, instrlimit, memlimit, 3758dfc11533SChris Williamson nvarg, outnvl)); 3759dfc11533SChris Williamson } 3760dfc11533SChris Williamson 376186714001SSerapheim Dimitropoulos /* 376286714001SSerapheim Dimitropoulos * innvl: unused 376386714001SSerapheim Dimitropoulos * outnvl: empty 376486714001SSerapheim Dimitropoulos */ 376586714001SSerapheim Dimitropoulos /* ARGSUSED */ 376686714001SSerapheim Dimitropoulos static int 376786714001SSerapheim Dimitropoulos zfs_ioc_pool_checkpoint(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 376886714001SSerapheim Dimitropoulos { 376986714001SSerapheim Dimitropoulos return (spa_checkpoint(poolname)); 377086714001SSerapheim Dimitropoulos } 377186714001SSerapheim Dimitropoulos 377286714001SSerapheim Dimitropoulos /* 377386714001SSerapheim Dimitropoulos * innvl: unused 377486714001SSerapheim Dimitropoulos * outnvl: empty 377586714001SSerapheim Dimitropoulos */ 377686714001SSerapheim Dimitropoulos /* ARGSUSED */ 377786714001SSerapheim Dimitropoulos static int 377886714001SSerapheim Dimitropoulos zfs_ioc_pool_discard_checkpoint(const char *poolname, nvlist_t *innvl, 377986714001SSerapheim Dimitropoulos nvlist_t *outnvl) 378086714001SSerapheim Dimitropoulos { 378186714001SSerapheim Dimitropoulos return (spa_checkpoint_discard(poolname)); 378286714001SSerapheim Dimitropoulos } 378386714001SSerapheim Dimitropoulos 37843cb34c60Sahrens /* 37853cb34c60Sahrens * inputs: 37863cb34c60Sahrens * zc_name name of dataset to destroy 3787842727c2SChris Kirby * zc_defer_destroy mark for deferred destroy 37883cb34c60Sahrens * 37893cb34c60Sahrens * outputs: none 37903cb34c60Sahrens */ 37911d452cf5Sahrens static int 37921d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 37931d452cf5Sahrens { 3794049ba636SAndriy Gapon objset_t *os; 3795049ba636SAndriy Gapon dmu_objset_type_t ost; 3796681d9761SEric Taylor int err; 3797fc7a6e3fSWill Andrews 3798049ba636SAndriy Gapon err = dmu_objset_hold(zc->zc_name, FTAG, &os); 3799049ba636SAndriy Gapon if (err != 0) 3800049ba636SAndriy Gapon return (err); 3801049ba636SAndriy Gapon ost = dmu_objset_type(os); 3802049ba636SAndriy Gapon dmu_objset_rele(os, FTAG); 3803049ba636SAndriy Gapon 3804049ba636SAndriy Gapon if (ost == DMU_OST_ZFS) 3805ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(zc->zc_name); 3806fa9e4066Sahrens 38076ccda740Sloli if (strchr(zc->zc_name, '@')) { 38083b2aab18SMatthew Ahrens err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy); 38096ccda740Sloli } else { 38103b2aab18SMatthew Ahrens err = dsl_destroy_head(zc->zc_name); 38116ccda740Sloli if (err == EEXIST) { 38126ccda740Sloli /* 38136ccda740Sloli * It is possible that the given DS may have 38146ccda740Sloli * hidden child (%recv) datasets - "leftovers" 38156ccda740Sloli * resulting from the previously interrupted 38166ccda740Sloli * 'zfs receive'. 38176ccda740Sloli * 38186ccda740Sloli * 6 extra bytes for /%recv 38196ccda740Sloli */ 38206ccda740Sloli char namebuf[ZFS_MAX_DATASET_NAME_LEN + 6]; 38216ccda740Sloli 38226ccda740Sloli if (snprintf(namebuf, sizeof (namebuf), "%s/%s", 38236ccda740Sloli zc->zc_name, recv_clone_name) >= 38246ccda740Sloli sizeof (namebuf)) 38256ccda740Sloli return (SET_ERROR(EINVAL)); 38266ccda740Sloli 38276ccda740Sloli /* 38286ccda740Sloli * Try to remove the hidden child (%recv) and after 38296ccda740Sloli * that try to remove the target dataset. 38306ccda740Sloli * If the hidden child (%recv) does not exist 38316ccda740Sloli * the original error (EEXIST) will be returned 38326ccda740Sloli */ 38336ccda740Sloli err = dsl_destroy_head(namebuf); 38346ccda740Sloli if (err == 0) 38356ccda740Sloli err = dsl_destroy_head(zc->zc_name); 38366ccda740Sloli else if (err == ENOENT) 38376ccda740Sloli err = SET_ERROR(EEXIST); 38386ccda740Sloli } 38396ccda740Sloli } 3840049ba636SAndriy Gapon if (ost == DMU_OST_ZVOL && err == 0) 38415c987a37SChris Kirby (void) zvol_remove_minor(zc->zc_name); 3842681d9761SEric Taylor return (err); 3843fa9e4066Sahrens } 3844fa9e4066Sahrens 3845094e47e9SGeorge Wilson /* 3846094e47e9SGeorge Wilson * innvl: { 3847*084fd14fSBrian Behlendorf * "initialize_command" -> POOL_INITIALIZE_{CANCEL|START|SUSPEND} (uint64) 3848*084fd14fSBrian Behlendorf * "initialize_vdevs": { -> guids to initialize (nvlist) 3849*084fd14fSBrian Behlendorf * "vdev_path_1": vdev_guid_1, (uint64), 3850*084fd14fSBrian Behlendorf * "vdev_path_2": vdev_guid_2, (uint64), 3851*084fd14fSBrian Behlendorf * ... 3852094e47e9SGeorge Wilson * }, 3853094e47e9SGeorge Wilson * } 3854094e47e9SGeorge Wilson * 3855094e47e9SGeorge Wilson * outnvl: { 3856*084fd14fSBrian Behlendorf * "initialize_vdevs": { -> initialization errors (nvlist) 3857*084fd14fSBrian Behlendorf * "vdev_path_1": errno, see function body for possible errnos (uint64) 3858*084fd14fSBrian Behlendorf * "vdev_path_2": errno, ... (uint64) 3859094e47e9SGeorge Wilson * ... 3860*084fd14fSBrian Behlendorf * } 3861094e47e9SGeorge Wilson * } 3862094e47e9SGeorge Wilson * 3863*084fd14fSBrian Behlendorf * EINVAL is returned for an unknown command or if any of the provided vdev 3864*084fd14fSBrian Behlendorf * guids have be specified with a type other than uint64. 3865094e47e9SGeorge Wilson */ 3866094e47e9SGeorge Wilson static int 3867094e47e9SGeorge Wilson zfs_ioc_pool_initialize(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 3868094e47e9SGeorge Wilson { 3869094e47e9SGeorge Wilson uint64_t cmd_type; 3870094e47e9SGeorge Wilson if (nvlist_lookup_uint64(innvl, ZPOOL_INITIALIZE_COMMAND, 3871094e47e9SGeorge Wilson &cmd_type) != 0) { 3872094e47e9SGeorge Wilson return (SET_ERROR(EINVAL)); 3873094e47e9SGeorge Wilson } 3874*084fd14fSBrian Behlendorf 3875094e47e9SGeorge Wilson if (!(cmd_type == POOL_INITIALIZE_CANCEL || 3876*084fd14fSBrian Behlendorf cmd_type == POOL_INITIALIZE_START || 3877094e47e9SGeorge Wilson cmd_type == POOL_INITIALIZE_SUSPEND)) { 3878094e47e9SGeorge Wilson return (SET_ERROR(EINVAL)); 3879094e47e9SGeorge Wilson } 3880094e47e9SGeorge Wilson 3881094e47e9SGeorge Wilson nvlist_t *vdev_guids; 3882094e47e9SGeorge Wilson if (nvlist_lookup_nvlist(innvl, ZPOOL_INITIALIZE_VDEVS, 3883094e47e9SGeorge Wilson &vdev_guids) != 0) { 3884094e47e9SGeorge Wilson return (SET_ERROR(EINVAL)); 3885094e47e9SGeorge Wilson } 3886094e47e9SGeorge Wilson 3887094e47e9SGeorge Wilson for (nvpair_t *pair = nvlist_next_nvpair(vdev_guids, NULL); 3888094e47e9SGeorge Wilson pair != NULL; pair = nvlist_next_nvpair(vdev_guids, pair)) { 3889*084fd14fSBrian Behlendorf uint64_t vdev_guid; 3890*084fd14fSBrian Behlendorf if (nvpair_value_uint64(pair, &vdev_guid) != 0) { 3891*084fd14fSBrian Behlendorf return (SET_ERROR(EINVAL)); 3892094e47e9SGeorge Wilson } 3893094e47e9SGeorge Wilson } 3894*084fd14fSBrian Behlendorf 3895*084fd14fSBrian Behlendorf spa_t *spa; 3896*084fd14fSBrian Behlendorf int error = spa_open(poolname, &spa, FTAG); 3897*084fd14fSBrian Behlendorf if (error != 0) 3898*084fd14fSBrian Behlendorf return (error); 3899*084fd14fSBrian Behlendorf 3900*084fd14fSBrian Behlendorf nvlist_t *vdev_errlist = fnvlist_alloc(); 3901*084fd14fSBrian Behlendorf int total_errors = spa_vdev_initialize(spa, vdev_guids, cmd_type, 3902*084fd14fSBrian Behlendorf vdev_errlist); 3903*084fd14fSBrian Behlendorf 3904094e47e9SGeorge Wilson if (fnvlist_size(vdev_errlist) > 0) { 3905094e47e9SGeorge Wilson fnvlist_add_nvlist(outnvl, ZPOOL_INITIALIZE_VDEVS, 3906094e47e9SGeorge Wilson vdev_errlist); 3907094e47e9SGeorge Wilson } 3908094e47e9SGeorge Wilson fnvlist_free(vdev_errlist); 3909094e47e9SGeorge Wilson 3910094e47e9SGeorge Wilson spa_close(spa, FTAG); 3911094e47e9SGeorge Wilson return (total_errors > 0 ? EINVAL : 0); 3912094e47e9SGeorge Wilson } 3913094e47e9SGeorge Wilson 3914*084fd14fSBrian Behlendorf /* 3915*084fd14fSBrian Behlendorf * innvl: { 3916*084fd14fSBrian Behlendorf * "trim_command" -> POOL_TRIM_{CANCEL|START|SUSPEND} (uint64) 3917*084fd14fSBrian Behlendorf * "trim_vdevs": { -> guids to TRIM (nvlist) 3918*084fd14fSBrian Behlendorf * "vdev_path_1": vdev_guid_1, (uint64), 3919*084fd14fSBrian Behlendorf * "vdev_path_2": vdev_guid_2, (uint64), 3920*084fd14fSBrian Behlendorf * ... 3921*084fd14fSBrian Behlendorf * }, 3922*084fd14fSBrian Behlendorf * "trim_rate" -> Target TRIM rate in bytes/sec. 3923*084fd14fSBrian Behlendorf * "trim_secure" -> Set to request a secure TRIM. 3924*084fd14fSBrian Behlendorf * } 3925*084fd14fSBrian Behlendorf * 3926*084fd14fSBrian Behlendorf * outnvl: { 3927*084fd14fSBrian Behlendorf * "trim_vdevs": { -> TRIM errors (nvlist) 3928*084fd14fSBrian Behlendorf * "vdev_path_1": errno, see function body for possible errnos (uint64) 3929*084fd14fSBrian Behlendorf * "vdev_path_2": errno, ... (uint64) 3930*084fd14fSBrian Behlendorf * ... 3931*084fd14fSBrian Behlendorf * } 3932*084fd14fSBrian Behlendorf * } 3933*084fd14fSBrian Behlendorf * 3934*084fd14fSBrian Behlendorf * EINVAL is returned for an unknown command or if any of the provided vdev 3935*084fd14fSBrian Behlendorf * guids have be specified with a type other than uint64. 3936*084fd14fSBrian Behlendorf */ 3937*084fd14fSBrian Behlendorf 3938*084fd14fSBrian Behlendorf static int 3939*084fd14fSBrian Behlendorf zfs_ioc_pool_trim(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 3940*084fd14fSBrian Behlendorf { 3941*084fd14fSBrian Behlendorf uint64_t cmd_type; 3942*084fd14fSBrian Behlendorf if (nvlist_lookup_uint64(innvl, ZPOOL_TRIM_COMMAND, &cmd_type) != 0) 3943*084fd14fSBrian Behlendorf return (SET_ERROR(EINVAL)); 3944*084fd14fSBrian Behlendorf 3945*084fd14fSBrian Behlendorf if (!(cmd_type == POOL_TRIM_CANCEL || 3946*084fd14fSBrian Behlendorf cmd_type == POOL_TRIM_START || 3947*084fd14fSBrian Behlendorf cmd_type == POOL_TRIM_SUSPEND)) { 3948*084fd14fSBrian Behlendorf return (SET_ERROR(EINVAL)); 3949*084fd14fSBrian Behlendorf } 3950*084fd14fSBrian Behlendorf 3951*084fd14fSBrian Behlendorf nvlist_t *vdev_guids; 3952*084fd14fSBrian Behlendorf if (nvlist_lookup_nvlist(innvl, ZPOOL_TRIM_VDEVS, &vdev_guids) != 0) 3953*084fd14fSBrian Behlendorf return (SET_ERROR(EINVAL)); 3954*084fd14fSBrian Behlendorf 3955*084fd14fSBrian Behlendorf for (nvpair_t *pair = nvlist_next_nvpair(vdev_guids, NULL); 3956*084fd14fSBrian Behlendorf pair != NULL; pair = nvlist_next_nvpair(vdev_guids, pair)) { 3957*084fd14fSBrian Behlendorf uint64_t vdev_guid; 3958*084fd14fSBrian Behlendorf if (nvpair_value_uint64(pair, &vdev_guid) != 0) { 3959*084fd14fSBrian Behlendorf return (SET_ERROR(EINVAL)); 3960*084fd14fSBrian Behlendorf } 3961*084fd14fSBrian Behlendorf } 3962*084fd14fSBrian Behlendorf 3963*084fd14fSBrian Behlendorf /* Optional, defaults to maximum rate when not provided */ 3964*084fd14fSBrian Behlendorf uint64_t rate; 3965*084fd14fSBrian Behlendorf if (nvlist_lookup_uint64(innvl, ZPOOL_TRIM_RATE, &rate) != 0) 3966*084fd14fSBrian Behlendorf rate = 0; 3967*084fd14fSBrian Behlendorf 3968*084fd14fSBrian Behlendorf /* Optional, defaults to standard TRIM when not provided */ 3969*084fd14fSBrian Behlendorf boolean_t secure; 3970*084fd14fSBrian Behlendorf if (nvlist_lookup_boolean_value(innvl, ZPOOL_TRIM_SECURE, 3971*084fd14fSBrian Behlendorf &secure) != 0) { 3972*084fd14fSBrian Behlendorf secure = B_FALSE; 3973*084fd14fSBrian Behlendorf } 3974*084fd14fSBrian Behlendorf 3975*084fd14fSBrian Behlendorf spa_t *spa; 3976*084fd14fSBrian Behlendorf int error = spa_open(poolname, &spa, FTAG); 3977*084fd14fSBrian Behlendorf if (error != 0) 3978*084fd14fSBrian Behlendorf return (error); 3979*084fd14fSBrian Behlendorf 3980*084fd14fSBrian Behlendorf nvlist_t *vdev_errlist = fnvlist_alloc(); 3981*084fd14fSBrian Behlendorf int total_errors = spa_vdev_trim(spa, vdev_guids, cmd_type, 3982*084fd14fSBrian Behlendorf rate, !!zfs_trim_metaslab_skip, secure, vdev_errlist); 3983*084fd14fSBrian Behlendorf 3984*084fd14fSBrian Behlendorf if (fnvlist_size(vdev_errlist) > 0) 3985*084fd14fSBrian Behlendorf fnvlist_add_nvlist(outnvl, ZPOOL_TRIM_VDEVS, vdev_errlist); 3986*084fd14fSBrian Behlendorf 3987*084fd14fSBrian Behlendorf fnvlist_free(vdev_errlist); 3988*084fd14fSBrian Behlendorf 3989*084fd14fSBrian Behlendorf spa_close(spa, FTAG); 3990*084fd14fSBrian Behlendorf return (total_errors > 0 ? EINVAL : 0); 3991*084fd14fSBrian Behlendorf } 3992*084fd14fSBrian Behlendorf 39933cb34c60Sahrens /* 3994a7027df1SMatthew Ahrens * fsname is name of dataset to rollback (to most recent snapshot) 39953cb34c60Sahrens * 399677b17137SAndriy Gapon * innvl may contain name of expected target snapshot 3997a7027df1SMatthew Ahrens * 3998a7027df1SMatthew Ahrens * outnvl: "target" -> name of most recent snapshot 3999a7027df1SMatthew Ahrens * } 40003cb34c60Sahrens */ 4001a7027df1SMatthew Ahrens /* ARGSUSED */ 4002fa9e4066Sahrens static int 400377b17137SAndriy Gapon zfs_ioc_rollback(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 4004fa9e4066Sahrens { 4005ae46e4c7SMatthew Ahrens zfsvfs_t *zfsvfs; 400677b17137SAndriy Gapon char *target = NULL; 40073b2aab18SMatthew Ahrens int error; 4008ae46e4c7SMatthew Ahrens 400977b17137SAndriy Gapon (void) nvlist_lookup_string(innvl, "target", &target); 401077b17137SAndriy Gapon if (target != NULL) { 401195643f75SAndriy Gapon const char *cp = strchr(target, '@'); 401277b17137SAndriy Gapon 401395643f75SAndriy Gapon /* 401495643f75SAndriy Gapon * The snap name must contain an @, and the part after it must 401595643f75SAndriy Gapon * contain only valid characters. 401695643f75SAndriy Gapon */ 401795643f75SAndriy Gapon if (cp == NULL || 401895643f75SAndriy Gapon zfs_component_namecheck(cp + 1, NULL, NULL) != 0) 401977b17137SAndriy Gapon return (SET_ERROR(EINVAL)); 402077b17137SAndriy Gapon } 402177b17137SAndriy Gapon 4022a7027df1SMatthew Ahrens if (getzfsvfs(fsname, &zfsvfs) == 0) { 4023690041b9SAndriy Gapon dsl_dataset_t *ds; 4024690041b9SAndriy Gapon 4025690041b9SAndriy Gapon ds = dmu_objset_ds(zfsvfs->z_os); 4026503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 402747f263f4Sek if (error == 0) { 402847f263f4Sek int resume_err; 40294ccbb6e7Sahrens 403077b17137SAndriy Gapon error = dsl_dataset_rollback(fsname, target, zfsvfs, 403177b17137SAndriy Gapon outnvl); 4032690041b9SAndriy Gapon resume_err = zfs_resume_fs(zfsvfs, ds); 403347f263f4Sek error = error ? error : resume_err; 403447f263f4Sek } 40354ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 40364ccbb6e7Sahrens } else { 403777b17137SAndriy Gapon error = dsl_dataset_rollback(fsname, target, NULL, outnvl); 40384ccbb6e7Sahrens } 40393b2aab18SMatthew Ahrens return (error); 40403b2aab18SMatthew Ahrens } 40414ccbb6e7Sahrens 40423b2aab18SMatthew Ahrens static int 40433b2aab18SMatthew Ahrens recursive_unmount(const char *fsname, void *arg) 40443b2aab18SMatthew Ahrens { 40453b2aab18SMatthew Ahrens const char *snapname = arg; 40469adfa60dSMatthew Ahrens char fullname[ZFS_MAX_DATASET_NAME_LEN]; 4047ae46e4c7SMatthew Ahrens 40483b2aab18SMatthew Ahrens (void) snprintf(fullname, sizeof (fullname), "%s@%s", fsname, snapname); 4049ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(fullname); 4050ed992b0aSSerapheim Dimitropoulos 4051ed992b0aSSerapheim Dimitropoulos return (0); 4052fa9e4066Sahrens } 4053fa9e4066Sahrens 40543cb34c60Sahrens /* 40553cb34c60Sahrens * inputs: 40563cb34c60Sahrens * zc_name old name of dataset 40573cb34c60Sahrens * zc_value new name of dataset 40583cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 40593cb34c60Sahrens * 40603cb34c60Sahrens * outputs: none 40613cb34c60Sahrens */ 4062fa9e4066Sahrens static int 4063fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 4064fa9e4066Sahrens { 4065049ba636SAndriy Gapon objset_t *os; 4066049ba636SAndriy Gapon dmu_objset_type_t ost; 40677f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 40683b2aab18SMatthew Ahrens char *at; 4069049ba636SAndriy Gapon int err; 4070cdf5b4caSmmusante 4071add927f8Sloli /* "zfs rename" from and to ...%recv datasets should both fail */ 4072add927f8Sloli zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 4073e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 4074add927f8Sloli if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 || 4075add927f8Sloli dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 4076add927f8Sloli strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%')) 4077be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 4078fa9e4066Sahrens 4079049ba636SAndriy Gapon err = dmu_objset_hold(zc->zc_name, FTAG, &os); 4080049ba636SAndriy Gapon if (err != 0) 4081049ba636SAndriy Gapon return (err); 4082049ba636SAndriy Gapon ost = dmu_objset_type(os); 4083049ba636SAndriy Gapon dmu_objset_rele(os, FTAG); 4084049ba636SAndriy Gapon 40853b2aab18SMatthew Ahrens at = strchr(zc->zc_name, '@'); 40863b2aab18SMatthew Ahrens if (at != NULL) { 40873b2aab18SMatthew Ahrens /* snaps must be in same fs */ 4088a0c1127bSSteven Hartland int error; 4089a0c1127bSSteven Hartland 40903b2aab18SMatthew Ahrens if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) 4091be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 40923b2aab18SMatthew Ahrens *at = '\0'; 4093049ba636SAndriy Gapon if (ost == DMU_OST_ZFS) { 4094a0c1127bSSteven Hartland error = dmu_objset_find(zc->zc_name, 40953b2aab18SMatthew Ahrens recursive_unmount, at + 1, 40963b2aab18SMatthew Ahrens recursive ? DS_FIND_CHILDREN : 0); 4097a0c1127bSSteven Hartland if (error != 0) { 4098a0c1127bSSteven Hartland *at = '@'; 40993b2aab18SMatthew Ahrens return (error); 4100a0c1127bSSteven Hartland } 41013b2aab18SMatthew Ahrens } 4102a0c1127bSSteven Hartland error = dsl_dataset_rename_snapshot(zc->zc_name, 4103a0c1127bSSteven Hartland at + 1, strchr(zc->zc_value, '@') + 1, recursive); 4104a0c1127bSSteven Hartland *at = '@'; 4105a0c1127bSSteven Hartland 4106a0c1127bSSteven Hartland return (error); 41073b2aab18SMatthew Ahrens } else { 4108049ba636SAndriy Gapon if (ost == DMU_OST_ZVOL) 41093b2aab18SMatthew Ahrens (void) zvol_remove_minor(zc->zc_name); 41103b2aab18SMatthew Ahrens return (dsl_dir_rename(zc->zc_name, zc->zc_value)); 4111fa9e4066Sahrens } 4112fa9e4066Sahrens } 4113fa9e4066Sahrens 411492241e0bSTom Erickson static int 411592241e0bSTom Erickson zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) 411692241e0bSTom Erickson { 411792241e0bSTom Erickson const char *propname = nvpair_name(pair); 411892241e0bSTom Erickson boolean_t issnap = (strchr(dsname, '@') != NULL); 411992241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 412092241e0bSTom Erickson uint64_t intval; 412192241e0bSTom Erickson int err; 412292241e0bSTom Erickson 412392241e0bSTom Erickson if (prop == ZPROP_INVAL) { 412492241e0bSTom Erickson if (zfs_prop_user(propname)) { 412592241e0bSTom Erickson if (err = zfs_secpolicy_write_perms(dsname, 412692241e0bSTom Erickson ZFS_DELEG_PERM_USERPROP, cr)) 412792241e0bSTom Erickson return (err); 412892241e0bSTom Erickson return (0); 412992241e0bSTom Erickson } 413092241e0bSTom Erickson 413192241e0bSTom Erickson if (!issnap && zfs_prop_userquota(propname)) { 413292241e0bSTom Erickson const char *perm = NULL; 413392241e0bSTom Erickson const char *uq_prefix = 413492241e0bSTom Erickson zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA]; 413592241e0bSTom Erickson const char *gq_prefix = 413692241e0bSTom Erickson zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA]; 4137f67950b2SNasf-Fan const char *uiq_prefix = 4138f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA]; 4139f67950b2SNasf-Fan const char *giq_prefix = 4140f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA]; 4141f67950b2SNasf-Fan const char *pq_prefix = 4142f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_PROJECTQUOTA]; 4143f67950b2SNasf-Fan const char *piq_prefix = zfs_userquota_prop_prefixes[\ 4144f67950b2SNasf-Fan ZFS_PROP_PROJECTOBJQUOTA]; 414592241e0bSTom Erickson 414692241e0bSTom Erickson if (strncmp(propname, uq_prefix, 414792241e0bSTom Erickson strlen(uq_prefix)) == 0) { 414892241e0bSTom Erickson perm = ZFS_DELEG_PERM_USERQUOTA; 4149f67950b2SNasf-Fan } else if (strncmp(propname, uiq_prefix, 4150f67950b2SNasf-Fan strlen(uiq_prefix)) == 0) { 4151f67950b2SNasf-Fan perm = ZFS_DELEG_PERM_USEROBJQUOTA; 415292241e0bSTom Erickson } else if (strncmp(propname, gq_prefix, 415392241e0bSTom Erickson strlen(gq_prefix)) == 0) { 415492241e0bSTom Erickson perm = ZFS_DELEG_PERM_GROUPQUOTA; 4155f67950b2SNasf-Fan } else if (strncmp(propname, giq_prefix, 4156f67950b2SNasf-Fan strlen(giq_prefix)) == 0) { 4157f67950b2SNasf-Fan perm = ZFS_DELEG_PERM_GROUPOBJQUOTA; 4158f67950b2SNasf-Fan } else if (strncmp(propname, pq_prefix, 4159f67950b2SNasf-Fan strlen(pq_prefix)) == 0) { 4160f67950b2SNasf-Fan perm = ZFS_DELEG_PERM_PROJECTQUOTA; 4161f67950b2SNasf-Fan } else if (strncmp(propname, piq_prefix, 4162f67950b2SNasf-Fan strlen(piq_prefix)) == 0) { 4163f67950b2SNasf-Fan perm = ZFS_DELEG_PERM_PROJECTOBJQUOTA; 416492241e0bSTom Erickson } else { 4165f67950b2SNasf-Fan /* {USER|GROUP|PROJECT}USED are read-only */ 4166be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 416792241e0bSTom Erickson } 416892241e0bSTom Erickson 416992241e0bSTom Erickson if (err = zfs_secpolicy_write_perms(dsname, perm, cr)) 417092241e0bSTom Erickson return (err); 417192241e0bSTom Erickson return (0); 417292241e0bSTom Erickson } 417392241e0bSTom Erickson 4174be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 417592241e0bSTom Erickson } 417692241e0bSTom Erickson 417792241e0bSTom Erickson if (issnap) 4178be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 417992241e0bSTom Erickson 418092241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 418192241e0bSTom Erickson /* 418292241e0bSTom Erickson * dsl_prop_get_all_impl() returns properties in this 418392241e0bSTom Erickson * format. 418492241e0bSTom Erickson */ 418592241e0bSTom Erickson nvlist_t *attrs; 418692241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 418792241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 418892241e0bSTom Erickson &pair) == 0); 418992241e0bSTom Erickson } 419092241e0bSTom Erickson 419192241e0bSTom Erickson /* 419292241e0bSTom Erickson * Check that this value is valid for this pool version 419392241e0bSTom Erickson */ 419492241e0bSTom Erickson switch (prop) { 419592241e0bSTom Erickson case ZFS_PROP_COMPRESSION: 419692241e0bSTom Erickson /* 419792241e0bSTom Erickson * If the user specified gzip compression, make sure 419892241e0bSTom Erickson * the SPA supports it. We ignore any errors here since 419992241e0bSTom Erickson * we'll catch them later. 420092241e0bSTom Erickson */ 4201b5152584SMatthew Ahrens if (nvpair_value_uint64(pair, &intval) == 0) { 420292241e0bSTom Erickson if (intval >= ZIO_COMPRESS_GZIP_1 && 420392241e0bSTom Erickson intval <= ZIO_COMPRESS_GZIP_9 && 420492241e0bSTom Erickson zfs_earlier_version(dsname, 420592241e0bSTom Erickson SPA_VERSION_GZIP_COMPRESSION)) { 4206be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 420792241e0bSTom Erickson } 420892241e0bSTom Erickson 420992241e0bSTom Erickson if (intval == ZIO_COMPRESS_ZLE && 421092241e0bSTom Erickson zfs_earlier_version(dsname, 421192241e0bSTom Erickson SPA_VERSION_ZLE_COMPRESSION)) 4212be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 421392241e0bSTom Erickson 4214a6f561b4SSašo Kiselkov if (intval == ZIO_COMPRESS_LZ4) { 4215a6f561b4SSašo Kiselkov spa_t *spa; 4216a6f561b4SSašo Kiselkov 4217a6f561b4SSašo Kiselkov if ((err = spa_open(dsname, &spa, FTAG)) != 0) 4218a6f561b4SSašo Kiselkov return (err); 4219a6f561b4SSašo Kiselkov 42202acef22dSMatthew Ahrens if (!spa_feature_is_enabled(spa, 42212acef22dSMatthew Ahrens SPA_FEATURE_LZ4_COMPRESS)) { 4222a6f561b4SSašo Kiselkov spa_close(spa, FTAG); 4223be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 4224a6f561b4SSašo Kiselkov } 4225a6f561b4SSašo Kiselkov spa_close(spa, FTAG); 4226a6f561b4SSašo Kiselkov } 4227a6f561b4SSašo Kiselkov 422892241e0bSTom Erickson /* 422992241e0bSTom Erickson * If this is a bootable dataset then 423092241e0bSTom Erickson * verify that the compression algorithm 423192241e0bSTom Erickson * is supported for booting. We must return 423292241e0bSTom Erickson * something other than ENOTSUP since it 423392241e0bSTom Erickson * implies a downrev pool version. 423492241e0bSTom Erickson */ 423592241e0bSTom Erickson if (zfs_is_bootfs(dsname) && 423692241e0bSTom Erickson !BOOTFS_COMPRESS_VALID(intval)) { 4237be6fd75aSMatthew Ahrens return (SET_ERROR(ERANGE)); 423892241e0bSTom Erickson } 423992241e0bSTom Erickson } 424092241e0bSTom Erickson break; 424192241e0bSTom Erickson 424292241e0bSTom Erickson case ZFS_PROP_COPIES: 424392241e0bSTom Erickson if (zfs_earlier_version(dsname, SPA_VERSION_DITTO_BLOCKS)) 4244be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 424592241e0bSTom Erickson break; 424692241e0bSTom Erickson 4247b5152584SMatthew Ahrens case ZFS_PROP_RECORDSIZE: 4248b5152584SMatthew Ahrens /* Record sizes above 128k need the feature to be enabled */ 4249b5152584SMatthew Ahrens if (nvpair_value_uint64(pair, &intval) == 0 && 4250b5152584SMatthew Ahrens intval > SPA_OLD_MAXBLOCKSIZE) { 4251b5152584SMatthew Ahrens spa_t *spa; 4252b5152584SMatthew Ahrens 4253b5152584SMatthew Ahrens /* 4254b5152584SMatthew Ahrens * We don't allow setting the property above 1MB, 4255b5152584SMatthew Ahrens * unless the tunable has been changed. 4256b5152584SMatthew Ahrens */ 4257b5152584SMatthew Ahrens if (intval > zfs_max_recordsize || 4258b5152584SMatthew Ahrens intval > SPA_MAXBLOCKSIZE) 42596de9bb56SMatthew Ahrens return (SET_ERROR(ERANGE)); 4260b5152584SMatthew Ahrens 4261b5152584SMatthew Ahrens if ((err = spa_open(dsname, &spa, FTAG)) != 0) 4262b5152584SMatthew Ahrens return (err); 4263b5152584SMatthew Ahrens 4264b5152584SMatthew Ahrens if (!spa_feature_is_enabled(spa, 4265b5152584SMatthew Ahrens SPA_FEATURE_LARGE_BLOCKS)) { 4266b5152584SMatthew Ahrens spa_close(spa, FTAG); 4267b5152584SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 4268b5152584SMatthew Ahrens } 4269b5152584SMatthew Ahrens spa_close(spa, FTAG); 4270b5152584SMatthew Ahrens } 4271b5152584SMatthew Ahrens break; 4272b5152584SMatthew Ahrens 427354811da5SToomas Soome case ZFS_PROP_DNODESIZE: 427454811da5SToomas Soome /* Dnode sizes above 512 need the feature to be enabled */ 427554811da5SToomas Soome if (nvpair_value_uint64(pair, &intval) == 0 && 427654811da5SToomas Soome intval != ZFS_DNSIZE_LEGACY) { 427754811da5SToomas Soome spa_t *spa; 427854811da5SToomas Soome 427954811da5SToomas Soome if ((err = spa_open(dsname, &spa, FTAG)) != 0) 428054811da5SToomas Soome return (err); 428154811da5SToomas Soome 428254811da5SToomas Soome if (!spa_feature_is_enabled(spa, 428354811da5SToomas Soome SPA_FEATURE_LARGE_DNODE)) { 428454811da5SToomas Soome spa_close(spa, FTAG); 428554811da5SToomas Soome return (SET_ERROR(ENOTSUP)); 428654811da5SToomas Soome } 428754811da5SToomas Soome spa_close(spa, FTAG); 428854811da5SToomas Soome } 428954811da5SToomas Soome break; 429054811da5SToomas Soome 4291663207adSDon Brady case ZFS_PROP_SPECIAL_SMALL_BLOCKS: 4292663207adSDon Brady /* 4293663207adSDon Brady * This property could require the allocation classes 4294663207adSDon Brady * feature to be active for setting, however we allow 4295663207adSDon Brady * it so that tests of settable properties succeed. 4296663207adSDon Brady * The CLI will issue a warning in this case. 4297663207adSDon Brady */ 4298663207adSDon Brady break; 4299663207adSDon Brady 430092241e0bSTom Erickson case ZFS_PROP_SHARESMB: 430192241e0bSTom Erickson if (zpl_earlier_version(dsname, ZPL_VERSION_FUID)) 4302be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 430392241e0bSTom Erickson break; 430492241e0bSTom Erickson 430592241e0bSTom Erickson case ZFS_PROP_ACLINHERIT: 430692241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_UINT64 && 430792241e0bSTom Erickson nvpair_value_uint64(pair, &intval) == 0) { 430892241e0bSTom Erickson if (intval == ZFS_ACL_PASSTHROUGH_X && 430992241e0bSTom Erickson zfs_earlier_version(dsname, 431092241e0bSTom Erickson SPA_VERSION_PASSTHROUGH_X)) 4311be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 431292241e0bSTom Erickson } 431392241e0bSTom Erickson break; 431445818ee1SMatthew Ahrens 431545818ee1SMatthew Ahrens case ZFS_PROP_CHECKSUM: 431645818ee1SMatthew Ahrens case ZFS_PROP_DEDUP: 431745818ee1SMatthew Ahrens { 431845818ee1SMatthew Ahrens spa_feature_t feature; 431945818ee1SMatthew Ahrens spa_t *spa; 432045818ee1SMatthew Ahrens 432145818ee1SMatthew Ahrens /* dedup feature version checks */ 432245818ee1SMatthew Ahrens if (prop == ZFS_PROP_DEDUP && 432345818ee1SMatthew Ahrens zfs_earlier_version(dsname, SPA_VERSION_DEDUP)) 432445818ee1SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 432545818ee1SMatthew Ahrens 432645818ee1SMatthew Ahrens if (nvpair_value_uint64(pair, &intval) != 0) 432745818ee1SMatthew Ahrens return (SET_ERROR(EINVAL)); 432845818ee1SMatthew Ahrens 432945818ee1SMatthew Ahrens /* check prop value is enabled in features */ 4330971640e6Silovezfs feature = zio_checksum_to_feature(intval & ZIO_CHECKSUM_MASK); 433145818ee1SMatthew Ahrens if (feature == SPA_FEATURE_NONE) 433245818ee1SMatthew Ahrens break; 433345818ee1SMatthew Ahrens 433445818ee1SMatthew Ahrens if ((err = spa_open(dsname, &spa, FTAG)) != 0) 433545818ee1SMatthew Ahrens return (err); 43360dd498c0SToomas Soome 433745818ee1SMatthew Ahrens if (!spa_feature_is_enabled(spa, feature)) { 433845818ee1SMatthew Ahrens spa_close(spa, FTAG); 433945818ee1SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 434045818ee1SMatthew Ahrens } 434145818ee1SMatthew Ahrens spa_close(spa, FTAG); 434245818ee1SMatthew Ahrens break; 434345818ee1SMatthew Ahrens } 434492241e0bSTom Erickson } 434592241e0bSTom Erickson 434692241e0bSTom Erickson return (zfs_secpolicy_setprop(dsname, prop, pair, CRED())); 434792241e0bSTom Erickson } 434892241e0bSTom Erickson 4349a6f561b4SSašo Kiselkov /* 4350a6f561b4SSašo Kiselkov * Checks for a race condition to make sure we don't increment a feature flag 4351a6f561b4SSašo Kiselkov * multiple times. 4352a6f561b4SSašo Kiselkov */ 4353a6f561b4SSašo Kiselkov static int 43543b2aab18SMatthew Ahrens zfs_prop_activate_feature_check(void *arg, dmu_tx_t *tx) 4355a6f561b4SSašo Kiselkov { 43563b2aab18SMatthew Ahrens spa_t *spa = dmu_tx_pool(tx)->dp_spa; 43572acef22dSMatthew Ahrens spa_feature_t *featurep = arg; 4358a6f561b4SSašo Kiselkov 43592acef22dSMatthew Ahrens if (!spa_feature_is_active(spa, *featurep)) 4360a6f561b4SSašo Kiselkov return (0); 4361a6f561b4SSašo Kiselkov else 4362be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 4363a6f561b4SSašo Kiselkov } 4364a6f561b4SSašo Kiselkov 4365a6f561b4SSašo Kiselkov /* 4366a6f561b4SSašo Kiselkov * The callback invoked on feature activation in the sync task caused by 4367a6f561b4SSašo Kiselkov * zfs_prop_activate_feature. 4368a6f561b4SSašo Kiselkov */ 4369a6f561b4SSašo Kiselkov static void 43703b2aab18SMatthew Ahrens zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx) 4371a6f561b4SSašo Kiselkov { 43723b2aab18SMatthew Ahrens spa_t *spa = dmu_tx_pool(tx)->dp_spa; 43732acef22dSMatthew Ahrens spa_feature_t *featurep = arg; 4374a6f561b4SSašo Kiselkov 43752acef22dSMatthew Ahrens spa_feature_incr(spa, *featurep, tx); 4376a6f561b4SSašo Kiselkov } 4377a6f561b4SSašo Kiselkov 43783b2aab18SMatthew Ahrens /* 43793b2aab18SMatthew Ahrens * Activates a feature on a pool in response to a property setting. This 43803b2aab18SMatthew Ahrens * creates a new sync task which modifies the pool to reflect the feature 43813b2aab18SMatthew Ahrens * as being active. 43823b2aab18SMatthew Ahrens */ 43833b2aab18SMatthew Ahrens static int 43842acef22dSMatthew Ahrens zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature) 43853b2aab18SMatthew Ahrens { 43863b2aab18SMatthew Ahrens int err; 43873b2aab18SMatthew Ahrens 43883b2aab18SMatthew Ahrens /* EBUSY here indicates that the feature is already active */ 43893b2aab18SMatthew Ahrens err = dsl_sync_task(spa_name(spa), 43903b2aab18SMatthew Ahrens zfs_prop_activate_feature_check, zfs_prop_activate_feature_sync, 43917d46dc6cSMatthew Ahrens &feature, 2, ZFS_SPACE_CHECK_RESERVED); 43923b2aab18SMatthew Ahrens 43933b2aab18SMatthew Ahrens if (err != 0 && err != EBUSY) 43943b2aab18SMatthew Ahrens return (err); 43953b2aab18SMatthew Ahrens else 43963b2aab18SMatthew Ahrens return (0); 43973b2aab18SMatthew Ahrens } 43983b2aab18SMatthew Ahrens 439992241e0bSTom Erickson /* 440092241e0bSTom Erickson * Removes properties from the given props list that fail permission checks 440192241e0bSTom Erickson * needed to clear them and to restore them in case of a receive error. For each 440292241e0bSTom Erickson * property, make sure we have both set and inherit permissions. 440392241e0bSTom Erickson * 440492241e0bSTom Erickson * Returns the first error encountered if any permission checks fail. If the 440592241e0bSTom Erickson * caller provides a non-NULL errlist, it also gives the complete list of names 440692241e0bSTom Erickson * of all the properties that failed a permission check along with the 440792241e0bSTom Erickson * corresponding error numbers. The caller is responsible for freeing the 440892241e0bSTom Erickson * returned errlist. 440992241e0bSTom Erickson * 441092241e0bSTom Erickson * If every property checks out successfully, zero is returned and the list 441192241e0bSTom Erickson * pointed at by errlist is NULL. 441292241e0bSTom Erickson */ 441392241e0bSTom Erickson static int 441492241e0bSTom Erickson zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) 4415745cd3c5Smaybee { 4416745cd3c5Smaybee zfs_cmd_t *zc; 441792241e0bSTom Erickson nvpair_t *pair, *next_pair; 441892241e0bSTom Erickson nvlist_t *errors; 441992241e0bSTom Erickson int err, rv = 0; 4420745cd3c5Smaybee 4421745cd3c5Smaybee if (props == NULL) 442292241e0bSTom Erickson return (0); 442392241e0bSTom Erickson 442492241e0bSTom Erickson VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 442592241e0bSTom Erickson 4426745cd3c5Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 4427745cd3c5Smaybee (void) strcpy(zc->zc_name, dataset); 442892241e0bSTom Erickson pair = nvlist_next_nvpair(props, NULL); 442992241e0bSTom Erickson while (pair != NULL) { 443092241e0bSTom Erickson next_pair = nvlist_next_nvpair(props, pair); 443192241e0bSTom Erickson 443292241e0bSTom Erickson (void) strcpy(zc->zc_value, nvpair_name(pair)); 443392241e0bSTom Erickson if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 || 44344445fffbSMatthew Ahrens (err = zfs_secpolicy_inherit_prop(zc, NULL, CRED())) != 0) { 443592241e0bSTom Erickson VERIFY(nvlist_remove_nvpair(props, pair) == 0); 443692241e0bSTom Erickson VERIFY(nvlist_add_int32(errors, 443792241e0bSTom Erickson zc->zc_value, err) == 0); 443892241e0bSTom Erickson } 443992241e0bSTom Erickson pair = next_pair; 4440745cd3c5Smaybee } 4441745cd3c5Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 444292241e0bSTom Erickson 444392241e0bSTom Erickson if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) { 444492241e0bSTom Erickson nvlist_free(errors); 444592241e0bSTom Erickson errors = NULL; 444692241e0bSTom Erickson } else { 444792241e0bSTom Erickson VERIFY(nvpair_value_int32(pair, &rv) == 0); 444892241e0bSTom Erickson } 444992241e0bSTom Erickson 445092241e0bSTom Erickson if (errlist == NULL) 445192241e0bSTom Erickson nvlist_free(errors); 445292241e0bSTom Erickson else 445392241e0bSTom Erickson *errlist = errors; 445492241e0bSTom Erickson 445592241e0bSTom Erickson return (rv); 445692241e0bSTom Erickson } 445792241e0bSTom Erickson 445892241e0bSTom Erickson static boolean_t 445992241e0bSTom Erickson propval_equals(nvpair_t *p1, nvpair_t *p2) 446092241e0bSTom Erickson { 446192241e0bSTom Erickson if (nvpair_type(p1) == DATA_TYPE_NVLIST) { 446292241e0bSTom Erickson /* dsl_prop_get_all_impl() format */ 446392241e0bSTom Erickson nvlist_t *attrs; 446492241e0bSTom Erickson VERIFY(nvpair_value_nvlist(p1, &attrs) == 0); 446592241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 446692241e0bSTom Erickson &p1) == 0); 446792241e0bSTom Erickson } 446892241e0bSTom Erickson 446992241e0bSTom Erickson if (nvpair_type(p2) == DATA_TYPE_NVLIST) { 447092241e0bSTom Erickson nvlist_t *attrs; 447192241e0bSTom Erickson VERIFY(nvpair_value_nvlist(p2, &attrs) == 0); 447292241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 447392241e0bSTom Erickson &p2) == 0); 447492241e0bSTom Erickson } 447592241e0bSTom Erickson 447692241e0bSTom Erickson if (nvpair_type(p1) != nvpair_type(p2)) 447792241e0bSTom Erickson return (B_FALSE); 447892241e0bSTom Erickson 447992241e0bSTom Erickson if (nvpair_type(p1) == DATA_TYPE_STRING) { 448092241e0bSTom Erickson char *valstr1, *valstr2; 448192241e0bSTom Erickson 448292241e0bSTom Erickson VERIFY(nvpair_value_string(p1, (char **)&valstr1) == 0); 448392241e0bSTom Erickson VERIFY(nvpair_value_string(p2, (char **)&valstr2) == 0); 448492241e0bSTom Erickson return (strcmp(valstr1, valstr2) == 0); 448592241e0bSTom Erickson } else { 448692241e0bSTom Erickson uint64_t intval1, intval2; 448792241e0bSTom Erickson 448892241e0bSTom Erickson VERIFY(nvpair_value_uint64(p1, &intval1) == 0); 448992241e0bSTom Erickson VERIFY(nvpair_value_uint64(p2, &intval2) == 0); 449092241e0bSTom Erickson return (intval1 == intval2); 449192241e0bSTom Erickson } 4492745cd3c5Smaybee } 4493745cd3c5Smaybee 449492241e0bSTom Erickson /* 449592241e0bSTom Erickson * Remove properties from props if they are not going to change (as determined 449692241e0bSTom Erickson * by comparison with origprops). Remove them from origprops as well, since we 449792241e0bSTom Erickson * do not need to clear or restore properties that won't change. 449892241e0bSTom Erickson */ 449992241e0bSTom Erickson static void 450092241e0bSTom Erickson props_reduce(nvlist_t *props, nvlist_t *origprops) 450192241e0bSTom Erickson { 450292241e0bSTom Erickson nvpair_t *pair, *next_pair; 450392241e0bSTom Erickson 450492241e0bSTom Erickson if (origprops == NULL) 450592241e0bSTom Erickson return; /* all props need to be received */ 450692241e0bSTom Erickson 450792241e0bSTom Erickson pair = nvlist_next_nvpair(props, NULL); 450892241e0bSTom Erickson while (pair != NULL) { 450992241e0bSTom Erickson const char *propname = nvpair_name(pair); 451092241e0bSTom Erickson nvpair_t *match; 451192241e0bSTom Erickson 451292241e0bSTom Erickson next_pair = nvlist_next_nvpair(props, pair); 451392241e0bSTom Erickson 451492241e0bSTom Erickson if ((nvlist_lookup_nvpair(origprops, propname, 451592241e0bSTom Erickson &match) != 0) || !propval_equals(pair, match)) 451692241e0bSTom Erickson goto next; /* need to set received value */ 451792241e0bSTom Erickson 451892241e0bSTom Erickson /* don't clear the existing received value */ 451992241e0bSTom Erickson (void) nvlist_remove_nvpair(origprops, match); 452092241e0bSTom Erickson /* don't bother receiving the property */ 452192241e0bSTom Erickson (void) nvlist_remove_nvpair(props, pair); 452292241e0bSTom Erickson next: 452392241e0bSTom Erickson pair = next_pair; 452492241e0bSTom Erickson } 452592241e0bSTom Erickson } 452692241e0bSTom Erickson 45275878fad7SDan McDonald /* 45285878fad7SDan McDonald * Extract properties that cannot be set PRIOR to the receipt of a dataset. 45295878fad7SDan McDonald * For example, refquota cannot be set until after the receipt of a dataset, 45305878fad7SDan McDonald * because in replication streams, an older/earlier snapshot may exceed the 45315878fad7SDan McDonald * refquota. We want to receive the older/earlier snapshot, but setting 45325878fad7SDan McDonald * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent 45335878fad7SDan McDonald * the older/earlier snapshot from being received (with EDQUOT). 45345878fad7SDan McDonald * 45355878fad7SDan McDonald * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario. 45365878fad7SDan McDonald * 45375878fad7SDan McDonald * libzfs will need to be judicious handling errors encountered by props 45385878fad7SDan McDonald * extracted by this function. 45395878fad7SDan McDonald */ 45405878fad7SDan McDonald static nvlist_t * 45415878fad7SDan McDonald extract_delay_props(nvlist_t *props) 45425878fad7SDan McDonald { 45435878fad7SDan McDonald nvlist_t *delayprops; 45445878fad7SDan McDonald nvpair_t *nvp, *tmp; 4545eb633035STom Caputi static const zfs_prop_t delayable[] = { 4546eb633035STom Caputi ZFS_PROP_REFQUOTA, 4547eb633035STom Caputi ZFS_PROP_KEYLOCATION, 4548eb633035STom Caputi 0 4549eb633035STom Caputi }; 45505878fad7SDan McDonald int i; 45515878fad7SDan McDonald 45525878fad7SDan McDonald VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 45535878fad7SDan McDonald 45545878fad7SDan McDonald for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL; 45555878fad7SDan McDonald nvp = nvlist_next_nvpair(props, nvp)) { 45565878fad7SDan McDonald /* 45575878fad7SDan McDonald * strcmp() is safe because zfs_prop_to_name() always returns 45585878fad7SDan McDonald * a bounded string. 45595878fad7SDan McDonald */ 45605878fad7SDan McDonald for (i = 0; delayable[i] != 0; i++) { 45615878fad7SDan McDonald if (strcmp(zfs_prop_to_name(delayable[i]), 45625878fad7SDan McDonald nvpair_name(nvp)) == 0) { 45635878fad7SDan McDonald break; 45645878fad7SDan McDonald } 45655878fad7SDan McDonald } 45665878fad7SDan McDonald if (delayable[i] != 0) { 45675878fad7SDan McDonald tmp = nvlist_prev_nvpair(props, nvp); 45685878fad7SDan McDonald VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0); 45695878fad7SDan McDonald VERIFY(nvlist_remove_nvpair(props, nvp) == 0); 45705878fad7SDan McDonald nvp = tmp; 45715878fad7SDan McDonald } 45725878fad7SDan McDonald } 45735878fad7SDan McDonald 45745878fad7SDan McDonald if (nvlist_empty(delayprops)) { 45755878fad7SDan McDonald nvlist_free(delayprops); 45765878fad7SDan McDonald delayprops = NULL; 45775878fad7SDan McDonald } 45785878fad7SDan McDonald return (delayprops); 45795878fad7SDan McDonald } 45805878fad7SDan McDonald 458192241e0bSTom Erickson #ifdef DEBUG 458292241e0bSTom Erickson static boolean_t zfs_ioc_recv_inject_err; 458392241e0bSTom Erickson #endif 458492241e0bSTom Erickson 45853cb34c60Sahrens /* 45866ccda740Sloli * nvlist 'errors' is always allocated. It will contain descriptions of 45876ccda740Sloli * encountered errors, if any. It's the callers responsibility to free. 45883cb34c60Sahrens */ 4589fa9e4066Sahrens static int 45906ccda740Sloli zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin, nvlist_t *recvprops, 45916ccda740Sloli nvlist_t *localprops, nvlist_t *hidden_args, boolean_t force, 45926ccda740Sloli boolean_t resumable, int input_fd, dmu_replay_record_t *begin_record, 45936ccda740Sloli int cleanup_fd, uint64_t *read_bytes, uint64_t *errflags, 45946ccda740Sloli uint64_t *action_handle, nvlist_t **errors) 4595fa9e4066Sahrens { 45963cb34c60Sahrens dmu_recv_cookie_t drc; 459792241e0bSTom Erickson int error = 0; 459892241e0bSTom Erickson int props_error = 0; 45993cb34c60Sahrens offset_t off; 46006ccda740Sloli nvlist_t *local_delayprops = NULL; 46016ccda740Sloli nvlist_t *recv_delayprops = NULL; 460292241e0bSTom Erickson nvlist_t *origprops = NULL; /* existing properties */ 46036ccda740Sloli nvlist_t *origrecvd = NULL; /* existing received properties */ 460492241e0bSTom Erickson boolean_t first_recvd_props = B_FALSE; 46056ccda740Sloli file_t *input_fp; 4606fa9e4066Sahrens 46076ccda740Sloli *read_bytes = 0; 46086ccda740Sloli *errflags = 0; 46096ccda740Sloli *errors = fnvlist_alloc(); 46103cb34c60Sahrens 46116ccda740Sloli input_fp = getf(input_fd); 46126ccda740Sloli if (input_fp == NULL) 4613be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 4614f18faf3fSek 46156ccda740Sloli error = dmu_recv_begin(tofs, tosnap, begin_record, force, 46166ccda740Sloli resumable, localprops, hidden_args, origin, &drc); 46173b2aab18SMatthew Ahrens if (error != 0) 46183b2aab18SMatthew Ahrens goto out; 46193b2aab18SMatthew Ahrens 46203b2aab18SMatthew Ahrens /* 46213b2aab18SMatthew Ahrens * Set properties before we receive the stream so that they are applied 46223b2aab18SMatthew Ahrens * to the new data. Note that we must call dmu_recv_stream() if 46233b2aab18SMatthew Ahrens * dmu_recv_begin() succeeds. 46243b2aab18SMatthew Ahrens */ 46256ccda740Sloli if (recvprops != NULL && !drc.drc_newfs) { 46263b2aab18SMatthew Ahrens if (spa_version(dsl_dataset_get_spa(drc.drc_ds)) >= 46273b2aab18SMatthew Ahrens SPA_VERSION_RECVD_PROPS && 46283b2aab18SMatthew Ahrens !dsl_prop_get_hasrecvd(tofs)) 462992241e0bSTom Erickson first_recvd_props = B_TRUE; 463092241e0bSTom Erickson 4631745cd3c5Smaybee /* 463292241e0bSTom Erickson * If new received properties are supplied, they are to 46336ccda740Sloli * completely replace the existing received properties, 46346ccda740Sloli * so stash away the existing ones. 4635745cd3c5Smaybee */ 46366ccda740Sloli if (dsl_prop_get_received(tofs, &origrecvd) == 0) { 463792241e0bSTom Erickson nvlist_t *errlist = NULL; 463892241e0bSTom Erickson /* 463992241e0bSTom Erickson * Don't bother writing a property if its value won't 464092241e0bSTom Erickson * change (and avoid the unnecessary security checks). 464192241e0bSTom Erickson * 464292241e0bSTom Erickson * The first receive after SPA_VERSION_RECVD_PROPS is a 464392241e0bSTom Erickson * special case where we blow away all local properties 464492241e0bSTom Erickson * regardless. 464592241e0bSTom Erickson */ 464692241e0bSTom Erickson if (!first_recvd_props) 46476ccda740Sloli props_reduce(recvprops, origrecvd); 46486ccda740Sloli if (zfs_check_clearable(tofs, origrecvd, &errlist) != 0) 46496ccda740Sloli (void) nvlist_merge(*errors, errlist, 0); 465092241e0bSTom Erickson nvlist_free(errlist); 46513cb34c60Sahrens 46526ccda740Sloli if (clear_received_props(tofs, origrecvd, 46536ccda740Sloli first_recvd_props ? NULL : recvprops) != 0) 46546ccda740Sloli *errflags |= ZPROP_ERR_NOCLEAR; 46556ccda740Sloli } else { 46566ccda740Sloli *errflags |= ZPROP_ERR_NOCLEAR; 46576ccda740Sloli } 46586ccda740Sloli } 46596ccda740Sloli 46606ccda740Sloli /* 46616ccda740Sloli * Stash away existing properties so we can restore them on error unless 46626ccda740Sloli * we're doing the first receive after SPA_VERSION_RECVD_PROPS, in which 46636ccda740Sloli * case "origrecvd" will take care of that. 46646ccda740Sloli */ 46656ccda740Sloli if (localprops != NULL && !drc.drc_newfs && !first_recvd_props) { 46666ccda740Sloli objset_t *os; 46676ccda740Sloli if (dmu_objset_hold(tofs, FTAG, &os) == 0) { 46686ccda740Sloli if (dsl_prop_get_all(os, &origprops) != 0) { 46696ccda740Sloli *errflags |= ZPROP_ERR_NOCLEAR; 46706ccda740Sloli } 46716ccda740Sloli dmu_objset_rele(os, FTAG); 46723b2aab18SMatthew Ahrens } else { 46736ccda740Sloli *errflags |= ZPROP_ERR_NOCLEAR; 467492241e0bSTom Erickson } 46753b2aab18SMatthew Ahrens } 467692241e0bSTom Erickson 46776ccda740Sloli if (recvprops != NULL) { 46783b2aab18SMatthew Ahrens props_error = dsl_prop_set_hasrecvd(tofs); 46793b2aab18SMatthew Ahrens 46803b2aab18SMatthew Ahrens if (props_error == 0) { 46816ccda740Sloli recv_delayprops = extract_delay_props(recvprops); 46823b2aab18SMatthew Ahrens (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, 46836ccda740Sloli recvprops, *errors); 46843b2aab18SMatthew Ahrens } 468592241e0bSTom Erickson } 468692241e0bSTom Erickson 46876ccda740Sloli if (localprops != NULL) { 46886ccda740Sloli nvlist_t *oprops = fnvlist_alloc(); 46896ccda740Sloli nvlist_t *xprops = fnvlist_alloc(); 46906ccda740Sloli nvpair_t *nvp = NULL; 46916ccda740Sloli 46926ccda740Sloli while ((nvp = nvlist_next_nvpair(localprops, nvp)) != NULL) { 46936ccda740Sloli if (nvpair_type(nvp) == DATA_TYPE_BOOLEAN) { 46946ccda740Sloli /* -x property */ 46956ccda740Sloli const char *name = nvpair_name(nvp); 46966ccda740Sloli zfs_prop_t prop = zfs_name_to_prop(name); 46976ccda740Sloli if (prop != ZPROP_INVAL) { 46986ccda740Sloli if (!zfs_prop_inheritable(prop)) 46996ccda740Sloli continue; 47006ccda740Sloli } else if (!zfs_prop_user(name)) 47016ccda740Sloli continue; 47026ccda740Sloli fnvlist_add_boolean(xprops, name); 47036ccda740Sloli } else { 47046ccda740Sloli /* -o property=value */ 47056ccda740Sloli fnvlist_add_nvpair(oprops, nvp); 47066ccda740Sloli } 47076ccda740Sloli } 47086ccda740Sloli 47096ccda740Sloli local_delayprops = extract_delay_props(oprops); 47106ccda740Sloli (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_LOCAL, 47116ccda740Sloli oprops, *errors); 47126ccda740Sloli (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_INHERITED, 47136ccda740Sloli xprops, *errors); 47146ccda740Sloli 47156ccda740Sloli nvlist_free(oprops); 47166ccda740Sloli nvlist_free(xprops); 47176ccda740Sloli } 47186ccda740Sloli 47196ccda740Sloli off = input_fp->f_offset; 47206ccda740Sloli error = dmu_recv_stream(&drc, input_fp->f_vnode, &off, cleanup_fd, 47216ccda740Sloli action_handle); 4722a2eea2e1Sahrens 4723f4b94bdeSMatthew Ahrens if (error == 0) { 4724f4b94bdeSMatthew Ahrens zfsvfs_t *zfsvfs = NULL; 4725745cd3c5Smaybee 4726f4b94bdeSMatthew Ahrens if (getzfsvfs(tofs, &zfsvfs) == 0) { 4727f4b94bdeSMatthew Ahrens /* online recv */ 4728690041b9SAndriy Gapon dsl_dataset_t *ds; 4729f4b94bdeSMatthew Ahrens int end_err; 4730745cd3c5Smaybee 4731690041b9SAndriy Gapon ds = dmu_objset_ds(zfsvfs->z_os); 4732503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 4733f4b94bdeSMatthew Ahrens /* 4734f4b94bdeSMatthew Ahrens * If the suspend fails, then the recv_end will 4735f4b94bdeSMatthew Ahrens * likely also fail, and clean up after itself. 4736f4b94bdeSMatthew Ahrens */ 473791948b51SKeith M Wesolowski end_err = dmu_recv_end(&drc, zfsvfs); 47385c703fceSGeorge Wilson if (error == 0) 4739690041b9SAndriy Gapon error = zfs_resume_fs(zfsvfs, ds); 4740f4b94bdeSMatthew Ahrens error = error ? error : end_err; 4741f4b94bdeSMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 4742745cd3c5Smaybee } else { 474391948b51SKeith M Wesolowski error = dmu_recv_end(&drc, NULL); 47443cb34c60Sahrens } 47455878fad7SDan McDonald 47465878fad7SDan McDonald /* Set delayed properties now, after we're done receiving. */ 47476ccda740Sloli if (recv_delayprops != NULL && error == 0) { 47485878fad7SDan McDonald (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, 47496ccda740Sloli recv_delayprops, *errors); 47506ccda740Sloli } 47516ccda740Sloli if (local_delayprops != NULL && error == 0) { 47526ccda740Sloli (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_LOCAL, 47536ccda740Sloli local_delayprops, *errors); 47545878fad7SDan McDonald } 47555878fad7SDan McDonald } 47565878fad7SDan McDonald 47575878fad7SDan McDonald /* 47586ccda740Sloli * Merge delayed props back in with initial props, in case 47596ccda740Sloli * we're DEBUG and zfs_ioc_recv_inject_err is set (which means 47606ccda740Sloli * we have to make sure clear_received_props() includes 47616ccda740Sloli * the delayed properties). 47626ccda740Sloli * 47636ccda740Sloli * Since zfs_ioc_recv_inject_err is only in DEBUG kernels, 47646ccda740Sloli * using ASSERT() will be just like a VERIFY. 47655878fad7SDan McDonald */ 47666ccda740Sloli if (recv_delayprops != NULL) { 47676ccda740Sloli ASSERT(nvlist_merge(recvprops, recv_delayprops, 0) == 0); 47686ccda740Sloli nvlist_free(recv_delayprops); 47696ccda740Sloli } 47706ccda740Sloli if (local_delayprops != NULL) { 47716ccda740Sloli ASSERT(nvlist_merge(localprops, local_delayprops, 0) == 0); 47726ccda740Sloli nvlist_free(local_delayprops); 477347f263f4Sek } 47743cb34c60Sahrens 47756ccda740Sloli *read_bytes = off - input_fp->f_offset; 47766ccda740Sloli if (VOP_SEEK(input_fp->f_vnode, input_fp->f_offset, &off, NULL) == 0) 47776ccda740Sloli input_fp->f_offset = off; 4778a2eea2e1Sahrens 477992241e0bSTom Erickson #ifdef DEBUG 478092241e0bSTom Erickson if (zfs_ioc_recv_inject_err) { 478192241e0bSTom Erickson zfs_ioc_recv_inject_err = B_FALSE; 478292241e0bSTom Erickson error = 1; 478392241e0bSTom Erickson } 478492241e0bSTom Erickson #endif 47856ccda740Sloli 4786745cd3c5Smaybee /* 4787745cd3c5Smaybee * On error, restore the original props. 4788745cd3c5Smaybee */ 47896ccda740Sloli if (error != 0 && recvprops != NULL && !drc.drc_newfs) { 47906ccda740Sloli if (clear_received_props(tofs, recvprops, NULL) != 0) { 47913b2aab18SMatthew Ahrens /* 47923b2aab18SMatthew Ahrens * We failed to clear the received properties. 47933b2aab18SMatthew Ahrens * Since we may have left a $recvd value on the 47943b2aab18SMatthew Ahrens * system, we can't clear the $hasrecvd flag. 47953b2aab18SMatthew Ahrens */ 47966ccda740Sloli *errflags |= ZPROP_ERR_NORESTORE; 47973b2aab18SMatthew Ahrens } else if (first_recvd_props) { 47983b2aab18SMatthew Ahrens dsl_prop_unset_hasrecvd(tofs); 479992241e0bSTom Erickson } 480092241e0bSTom Erickson 48016ccda740Sloli if (origrecvd == NULL && !drc.drc_newfs) { 480292241e0bSTom Erickson /* We failed to stash the original properties. */ 48036ccda740Sloli *errflags |= ZPROP_ERR_NORESTORE; 480492241e0bSTom Erickson } 480592241e0bSTom Erickson 480692241e0bSTom Erickson /* 480792241e0bSTom Erickson * dsl_props_set() will not convert RECEIVED to LOCAL on or 480892241e0bSTom Erickson * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL 48096ccda740Sloli * explicitly if we're restoring local properties cleared in the 481092241e0bSTom Erickson * first new-style receive. 481192241e0bSTom Erickson */ 48126ccda740Sloli if (origrecvd != NULL && 481392241e0bSTom Erickson zfs_set_prop_nvlist(tofs, (first_recvd_props ? 481492241e0bSTom Erickson ZPROP_SRC_LOCAL : ZPROP_SRC_RECEIVED), 48156ccda740Sloli origrecvd, NULL) != 0) { 481692241e0bSTom Erickson /* 481792241e0bSTom Erickson * We stashed the original properties but failed to 481892241e0bSTom Erickson * restore them. 481992241e0bSTom Erickson */ 48206ccda740Sloli *errflags |= ZPROP_ERR_NORESTORE; 482192241e0bSTom Erickson } 4822745cd3c5Smaybee } 48236ccda740Sloli if (error != 0 && localprops != NULL && !drc.drc_newfs && 48246ccda740Sloli !first_recvd_props) { 48256ccda740Sloli nvlist_t *setprops; 48266ccda740Sloli nvlist_t *inheritprops; 48276ccda740Sloli nvpair_t *nvp; 48286ccda740Sloli 48296ccda740Sloli if (origprops == NULL) { 48306ccda740Sloli /* We failed to stash the original properties. */ 48316ccda740Sloli *errflags |= ZPROP_ERR_NORESTORE; 48326ccda740Sloli goto out; 48336ccda740Sloli } 48346ccda740Sloli 48356ccda740Sloli /* Restore original props */ 48366ccda740Sloli setprops = fnvlist_alloc(); 48376ccda740Sloli inheritprops = fnvlist_alloc(); 48386ccda740Sloli nvp = NULL; 48396ccda740Sloli while ((nvp = nvlist_next_nvpair(localprops, nvp)) != NULL) { 48406ccda740Sloli const char *name = nvpair_name(nvp); 48416ccda740Sloli const char *source; 48426ccda740Sloli nvlist_t *attrs; 48436ccda740Sloli 48446ccda740Sloli if (!nvlist_exists(origprops, name)) { 48456ccda740Sloli /* 48466ccda740Sloli * Property was not present or was explicitly 48476ccda740Sloli * inherited before the receive, restore this. 48486ccda740Sloli */ 48496ccda740Sloli fnvlist_add_boolean(inheritprops, name); 48506ccda740Sloli continue; 48516ccda740Sloli } 48526ccda740Sloli attrs = fnvlist_lookup_nvlist(origprops, name); 48536ccda740Sloli source = fnvlist_lookup_string(attrs, ZPROP_SOURCE); 48546ccda740Sloli 48556ccda740Sloli /* Skip received properties */ 48566ccda740Sloli if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) 48576ccda740Sloli continue; 48586ccda740Sloli 48596ccda740Sloli if (strcmp(source, tofs) == 0) { 48606ccda740Sloli /* Property was locally set */ 48616ccda740Sloli fnvlist_add_nvlist(setprops, name, attrs); 48626ccda740Sloli } else { 48636ccda740Sloli /* Property was implicitly inherited */ 48646ccda740Sloli fnvlist_add_boolean(inheritprops, name); 48656ccda740Sloli } 48666ccda740Sloli } 48676ccda740Sloli 48686ccda740Sloli if (zfs_set_prop_nvlist(tofs, ZPROP_SRC_LOCAL, setprops, 48696ccda740Sloli NULL) != 0) 48706ccda740Sloli *errflags |= ZPROP_ERR_NORESTORE; 48716ccda740Sloli if (zfs_set_prop_nvlist(tofs, ZPROP_SRC_INHERITED, inheritprops, 48726ccda740Sloli NULL) != 0) 48736ccda740Sloli *errflags |= ZPROP_ERR_NORESTORE; 48746ccda740Sloli 48756ccda740Sloli nvlist_free(setprops); 48766ccda740Sloli nvlist_free(inheritprops); 48776ccda740Sloli } 4878745cd3c5Smaybee out: 48796ccda740Sloli releasef(input_fd); 48806ccda740Sloli nvlist_free(origrecvd); 4881745cd3c5Smaybee nvlist_free(origprops); 488292241e0bSTom Erickson 488392241e0bSTom Erickson if (error == 0) 488492241e0bSTom Erickson error = props_error; 488592241e0bSTom Erickson 4886fa9e4066Sahrens return (error); 4887fa9e4066Sahrens } 4888fa9e4066Sahrens 48896ccda740Sloli /* 48906ccda740Sloli * inputs: 48916ccda740Sloli * zc_name name of containing filesystem 48926ccda740Sloli * zc_nvlist_src{_size} nvlist of received properties to apply 48936ccda740Sloli * zc_nvlist_conf{_size} nvlist of local properties to apply 48946ccda740Sloli * zc_history_offset{_len} nvlist of hidden args { "wkeydata" -> value } 48956ccda740Sloli * zc_value name of snapshot to create 48966ccda740Sloli * zc_string name of clone origin (if DRR_FLAG_CLONE) 48976ccda740Sloli * zc_cookie file descriptor to recv from 48986ccda740Sloli * zc_begin_record the BEGIN record of the stream (not byteswapped) 48996ccda740Sloli * zc_guid force flag 49006ccda740Sloli * zc_cleanup_fd cleanup-on-exit file descriptor 49016ccda740Sloli * zc_action_handle handle for this guid/ds mapping (or zero on first call) 49026ccda740Sloli * zc_resumable if data is incomplete assume sender will resume 49036ccda740Sloli * 49046ccda740Sloli * outputs: 49056ccda740Sloli * zc_cookie number of bytes read 49066ccda740Sloli * zc_nvlist_dst{_size} error for each unapplied received property 49076ccda740Sloli * zc_obj zprop_errflags_t 49086ccda740Sloli * zc_action_handle handle for this guid/ds mapping 49096ccda740Sloli */ 49106ccda740Sloli static int 49116ccda740Sloli zfs_ioc_recv(zfs_cmd_t *zc) 49126ccda740Sloli { 49136ccda740Sloli dmu_replay_record_t begin_record; 49146ccda740Sloli nvlist_t *errors = NULL; 49156ccda740Sloli nvlist_t *recvdprops = NULL; 49166ccda740Sloli nvlist_t *localprops = NULL; 49176ccda740Sloli nvlist_t *hidden_args = NULL; 49186ccda740Sloli char *origin = NULL; 49196ccda740Sloli char *tosnap; 49206ccda740Sloli char tofs[ZFS_MAX_DATASET_NAME_LEN]; 49216ccda740Sloli int error = 0; 49226ccda740Sloli 49236ccda740Sloli if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 49246ccda740Sloli strchr(zc->zc_value, '@') == NULL || 49256ccda740Sloli strchr(zc->zc_value, '%')) 49266ccda740Sloli return (SET_ERROR(EINVAL)); 49276ccda740Sloli 49286ccda740Sloli (void) strlcpy(tofs, zc->zc_value, sizeof (tofs)); 49296ccda740Sloli tosnap = strchr(tofs, '@'); 49306ccda740Sloli *tosnap++ = '\0'; 49316ccda740Sloli 49326ccda740Sloli if (zc->zc_nvlist_src != 0 && 49336ccda740Sloli (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 49346ccda740Sloli zc->zc_iflags, &recvdprops)) != 0) 49356ccda740Sloli return (error); 49366ccda740Sloli 49376ccda740Sloli if (zc->zc_nvlist_conf != 0 && 49386ccda740Sloli (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 49396ccda740Sloli zc->zc_iflags, &localprops)) != 0) 49406ccda740Sloli return (error); 49416ccda740Sloli 49426ccda740Sloli if (zc->zc_history_offset != 0 && 49436ccda740Sloli (error = get_nvlist(zc->zc_history_offset, zc->zc_history_len, 49446ccda740Sloli zc->zc_iflags, &hidden_args)) != 0) 49456ccda740Sloli return (error); 49466ccda740Sloli 49476ccda740Sloli if (zc->zc_string[0]) 49486ccda740Sloli origin = zc->zc_string; 49496ccda740Sloli 49506ccda740Sloli begin_record.drr_type = DRR_BEGIN; 49516ccda740Sloli begin_record.drr_payloadlen = zc->zc_begin_record.drr_payloadlen; 49526ccda740Sloli begin_record.drr_u.drr_begin = zc->zc_begin_record.drr_u.drr_begin; 49536ccda740Sloli 49546ccda740Sloli error = zfs_ioc_recv_impl(tofs, tosnap, origin, recvdprops, localprops, 49556ccda740Sloli hidden_args, zc->zc_guid, zc->zc_resumable, zc->zc_cookie, 49566ccda740Sloli &begin_record, zc->zc_cleanup_fd, &zc->zc_cookie, &zc->zc_obj, 49576ccda740Sloli &zc->zc_action_handle, &errors); 49586ccda740Sloli nvlist_free(recvdprops); 49596ccda740Sloli nvlist_free(localprops); 49606ccda740Sloli 49616ccda740Sloli /* 49626ccda740Sloli * Now that all props, initial and delayed, are set, report the prop 49636ccda740Sloli * errors to the caller. 49646ccda740Sloli */ 49656ccda740Sloli if (zc->zc_nvlist_dst_size != 0 && errors != NULL && 49666ccda740Sloli (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 || 49676ccda740Sloli put_nvlist(zc, errors) != 0)) { 49686ccda740Sloli /* 49696ccda740Sloli * Caller made zc->zc_nvlist_dst less than the minimum expected 49706ccda740Sloli * size or supplied an invalid address. 49716ccda740Sloli */ 49726ccda740Sloli error = SET_ERROR(EINVAL); 49736ccda740Sloli } 49746ccda740Sloli 49756ccda740Sloli nvlist_free(errors); 49766ccda740Sloli 49776ccda740Sloli return (error); 49786ccda740Sloli } 49796ccda740Sloli 49803cb34c60Sahrens /* 49813cb34c60Sahrens * inputs: 49823cb34c60Sahrens * zc_name name of snapshot to send 49833cb34c60Sahrens * zc_cookie file descriptor to send stream to 4984a7f53a56SChris Kirby * zc_obj fromorigin flag (mutually exclusive with zc_fromobj) 4985a7f53a56SChris Kirby * zc_sendobj objsetid of snapshot to send 4986a7f53a56SChris Kirby * zc_fromobj objsetid of incremental fromsnap (may be zero) 498719b94df9SMatthew Ahrens * zc_guid if set, estimate size of stream only. zc_cookie is ignored. 498819b94df9SMatthew Ahrens * output size in zc_objset_type. 4989b5152584SMatthew Ahrens * zc_flags lzc_send_flags 49903cb34c60Sahrens * 499178f17100SMatthew Ahrens * outputs: 499278f17100SMatthew Ahrens * zc_objset_type estimated size, if zc_guid is set 49933cb34c60Sahrens */ 4994fa9e4066Sahrens static int 49953cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 4996fa9e4066Sahrens { 4997fa9e4066Sahrens int error; 49983cb34c60Sahrens offset_t off; 499919b94df9SMatthew Ahrens boolean_t estimate = (zc->zc_guid != 0); 50005d7b4d43SMatthew Ahrens boolean_t embedok = (zc->zc_flags & 0x1); 5001b5152584SMatthew Ahrens boolean_t large_block_ok = (zc->zc_flags & 0x2); 50025602294fSDan Kimmel boolean_t compressok = (zc->zc_flags & 0x4); 5003eb633035STom Caputi boolean_t rawok = (zc->zc_flags & 0x8); 5004fa9e4066Sahrens 50053b2aab18SMatthew Ahrens if (zc->zc_obj != 0) { 50063b2aab18SMatthew Ahrens dsl_pool_t *dp; 50073b2aab18SMatthew Ahrens dsl_dataset_t *tosnap; 5008a7f53a56SChris Kirby 50093b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 50103b2aab18SMatthew Ahrens if (error != 0) 5011a7f53a56SChris Kirby return (error); 50123b2aab18SMatthew Ahrens 50133b2aab18SMatthew Ahrens error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &tosnap); 50143b2aab18SMatthew Ahrens if (error != 0) { 50153b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 5016fa9e4066Sahrens return (error); 5017fa9e4066Sahrens } 50183b2aab18SMatthew Ahrens 50193b2aab18SMatthew Ahrens if (dsl_dir_is_clone(tosnap->ds_dir)) 5020c1379625SJustin T. Gibbs zc->zc_fromobj = 5021c1379625SJustin T. Gibbs dsl_dir_phys(tosnap->ds_dir)->dd_origin_obj; 50223b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 50233b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 50244445fffbSMatthew Ahrens } 50254445fffbSMatthew Ahrens 50263b2aab18SMatthew Ahrens if (estimate) { 50273b2aab18SMatthew Ahrens dsl_pool_t *dp; 50283b2aab18SMatthew Ahrens dsl_dataset_t *tosnap; 50293b2aab18SMatthew Ahrens dsl_dataset_t *fromsnap = NULL; 50304445fffbSMatthew Ahrens 50313b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 50323b2aab18SMatthew Ahrens if (error != 0) 50333b2aab18SMatthew Ahrens return (error); 50343b2aab18SMatthew Ahrens 5035eb633035STom Caputi error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, 5036eb633035STom Caputi FTAG, &tosnap); 50373b2aab18SMatthew Ahrens if (error != 0) { 50383b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 50393b2aab18SMatthew Ahrens return (error); 50404445fffbSMatthew Ahrens } 50414445fffbSMatthew Ahrens 50423b2aab18SMatthew Ahrens if (zc->zc_fromobj != 0) { 50433b2aab18SMatthew Ahrens error = dsl_dataset_hold_obj(dp, zc->zc_fromobj, 50443b2aab18SMatthew Ahrens FTAG, &fromsnap); 50453b2aab18SMatthew Ahrens if (error != 0) { 50463b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 50473b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 50484445fffbSMatthew Ahrens return (error); 50494445fffbSMatthew Ahrens } 50504445fffbSMatthew Ahrens } 5051fa9e4066Sahrens 5052eb633035STom Caputi error = dmu_send_estimate(tosnap, fromsnap, compressok || rawok, 505319b94df9SMatthew Ahrens &zc->zc_objset_type); 50543b2aab18SMatthew Ahrens 50553b2aab18SMatthew Ahrens if (fromsnap != NULL) 50563b2aab18SMatthew Ahrens dsl_dataset_rele(fromsnap, FTAG); 50573b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 50583b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 505919b94df9SMatthew Ahrens } else { 506019b94df9SMatthew Ahrens file_t *fp = getf(zc->zc_cookie); 50613b2aab18SMatthew Ahrens if (fp == NULL) 5062be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 5063fa9e4066Sahrens 506419b94df9SMatthew Ahrens off = fp->f_offset; 50653b2aab18SMatthew Ahrens error = dmu_send_obj(zc->zc_name, zc->zc_sendobj, 5066eb633035STom Caputi zc->zc_fromobj, embedok, large_block_ok, compressok, rawok, 5067b5152584SMatthew Ahrens zc->zc_cookie, fp->f_vnode, &off); 5068fa9e4066Sahrens 506919b94df9SMatthew Ahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 507019b94df9SMatthew Ahrens fp->f_offset = off; 507119b94df9SMatthew Ahrens releasef(zc->zc_cookie); 507219b94df9SMatthew Ahrens } 5073fa9e4066Sahrens return (error); 5074fa9e4066Sahrens } 5075fa9e4066Sahrens 50764e3c9f44SBill Pijewski /* 50774e3c9f44SBill Pijewski * inputs: 50784e3c9f44SBill Pijewski * zc_name name of snapshot on which to report progress 50794e3c9f44SBill Pijewski * zc_cookie file descriptor of send stream 50804e3c9f44SBill Pijewski * 50814e3c9f44SBill Pijewski * outputs: 50824e3c9f44SBill Pijewski * zc_cookie number of bytes written in send stream thus far 50834e3c9f44SBill Pijewski */ 50844e3c9f44SBill Pijewski static int 50854e3c9f44SBill Pijewski zfs_ioc_send_progress(zfs_cmd_t *zc) 50864e3c9f44SBill Pijewski { 50873b2aab18SMatthew Ahrens dsl_pool_t *dp; 50884e3c9f44SBill Pijewski dsl_dataset_t *ds; 50894e3c9f44SBill Pijewski dmu_sendarg_t *dsp = NULL; 50904e3c9f44SBill Pijewski int error; 50914e3c9f44SBill Pijewski 50923b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 50933b2aab18SMatthew Ahrens if (error != 0) 50943b2aab18SMatthew Ahrens return (error); 50953b2aab18SMatthew Ahrens 50963b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds); 50973b2aab18SMatthew Ahrens if (error != 0) { 50983b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 50994e3c9f44SBill Pijewski return (error); 51003b2aab18SMatthew Ahrens } 51014e3c9f44SBill Pijewski 51024e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 51034e3c9f44SBill Pijewski 51044e3c9f44SBill Pijewski /* 51054e3c9f44SBill Pijewski * Iterate over all the send streams currently active on this dataset. 51064e3c9f44SBill Pijewski * If there's one which matches the specified file descriptor _and_ the 51074e3c9f44SBill Pijewski * stream was started by the current process, return the progress of 51084e3c9f44SBill Pijewski * that stream. 51094e3c9f44SBill Pijewski */ 51104e3c9f44SBill Pijewski for (dsp = list_head(&ds->ds_sendstreams); dsp != NULL; 51114e3c9f44SBill Pijewski dsp = list_next(&ds->ds_sendstreams, dsp)) { 51124e3c9f44SBill Pijewski if (dsp->dsa_outfd == zc->zc_cookie && 51134e3c9f44SBill Pijewski dsp->dsa_proc == curproc) 51144e3c9f44SBill Pijewski break; 51154e3c9f44SBill Pijewski } 51164e3c9f44SBill Pijewski 51174e3c9f44SBill Pijewski if (dsp != NULL) 51184e3c9f44SBill Pijewski zc->zc_cookie = *(dsp->dsa_off); 51194e3c9f44SBill Pijewski else 5120be6fd75aSMatthew Ahrens error = SET_ERROR(ENOENT); 51214e3c9f44SBill Pijewski 51224e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 51234e3c9f44SBill Pijewski dsl_dataset_rele(ds, FTAG); 51243b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 51254e3c9f44SBill Pijewski return (error); 51264e3c9f44SBill Pijewski } 51274e3c9f44SBill Pijewski 5128ea8dc4b6Seschrock static int 5129ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 5130ea8dc4b6Seschrock { 5131ea8dc4b6Seschrock int id, error; 5132ea8dc4b6Seschrock 5133ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 5134ea8dc4b6Seschrock &zc->zc_inject_record); 5135ea8dc4b6Seschrock 5136ea8dc4b6Seschrock if (error == 0) 5137ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 5138ea8dc4b6Seschrock 5139ea8dc4b6Seschrock return (error); 5140ea8dc4b6Seschrock } 5141ea8dc4b6Seschrock 5142ea8dc4b6Seschrock static int 5143ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 5144ea8dc4b6Seschrock { 5145ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 5146ea8dc4b6Seschrock } 5147ea8dc4b6Seschrock 5148ea8dc4b6Seschrock static int 5149ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 5150ea8dc4b6Seschrock { 5151ea8dc4b6Seschrock int id = (int)zc->zc_guid; 5152ea8dc4b6Seschrock int error; 5153ea8dc4b6Seschrock 5154ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 5155ea8dc4b6Seschrock &zc->zc_inject_record); 5156ea8dc4b6Seschrock 5157ea8dc4b6Seschrock zc->zc_guid = id; 5158ea8dc4b6Seschrock 5159ea8dc4b6Seschrock return (error); 5160ea8dc4b6Seschrock } 5161ea8dc4b6Seschrock 5162ea8dc4b6Seschrock static int 5163ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 5164ea8dc4b6Seschrock { 5165ea8dc4b6Seschrock spa_t *spa; 5166ea8dc4b6Seschrock int error; 5167e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 5168ea8dc4b6Seschrock 5169ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 5170ea8dc4b6Seschrock return (error); 5171ea8dc4b6Seschrock 5172e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 5173ea8dc4b6Seschrock &count); 5174ea8dc4b6Seschrock if (error == 0) 5175e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 5176ea8dc4b6Seschrock else 5177e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 5178ea8dc4b6Seschrock 5179ea8dc4b6Seschrock spa_close(spa, FTAG); 5180ea8dc4b6Seschrock 5181ea8dc4b6Seschrock return (error); 5182ea8dc4b6Seschrock } 5183ea8dc4b6Seschrock 5184ea8dc4b6Seschrock static int 5185ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 5186ea8dc4b6Seschrock { 5187ea8dc4b6Seschrock spa_t *spa; 5188ea8dc4b6Seschrock vdev_t *vd; 5189bb8b5132Sek int error; 5190ea8dc4b6Seschrock 5191b87f3af3Sperrin /* 5192b87f3af3Sperrin * On zpool clear we also fix up missing slogs 5193b87f3af3Sperrin */ 5194b87f3af3Sperrin mutex_enter(&spa_namespace_lock); 5195b87f3af3Sperrin spa = spa_lookup(zc->zc_name); 5196b87f3af3Sperrin if (spa == NULL) { 5197b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 5198be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 5199b87f3af3Sperrin } 5200b24ab676SJeff Bonwick if (spa_get_log_state(spa) == SPA_LOG_MISSING) { 5201b87f3af3Sperrin /* we need to let spa_open/spa_load clear the chains */ 5202b24ab676SJeff Bonwick spa_set_log_state(spa, SPA_LOG_CLEAR); 5203b87f3af3Sperrin } 5204468c413aSTim Haley spa->spa_last_open_failed = 0; 5205b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 5206b87f3af3Sperrin 5207c8ee1847SVictor Latushkin if (zc->zc_cookie & ZPOOL_NO_REWIND) { 5208468c413aSTim Haley error = spa_open(zc->zc_name, &spa, FTAG); 5209468c413aSTim Haley } else { 5210468c413aSTim Haley nvlist_t *policy; 5211468c413aSTim Haley nvlist_t *config = NULL; 5212468c413aSTim Haley 5213dd328bf6SToomas Soome if (zc->zc_nvlist_src == 0) 5214be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5215468c413aSTim Haley 5216468c413aSTim Haley if ((error = get_nvlist(zc->zc_nvlist_src, 5217468c413aSTim Haley zc->zc_nvlist_src_size, zc->zc_iflags, &policy)) == 0) { 5218468c413aSTim Haley error = spa_open_rewind(zc->zc_name, &spa, FTAG, 5219468c413aSTim Haley policy, &config); 5220468c413aSTim Haley if (config != NULL) { 52214b964adaSGeorge Wilson int err; 52224b964adaSGeorge Wilson 52234b964adaSGeorge Wilson if ((err = put_nvlist(zc, config)) != 0) 52244b964adaSGeorge Wilson error = err; 5225468c413aSTim Haley nvlist_free(config); 5226468c413aSTim Haley } 5227468c413aSTim Haley nvlist_free(policy); 5228468c413aSTim Haley } 5229468c413aSTim Haley } 5230468c413aSTim Haley 52313b2aab18SMatthew Ahrens if (error != 0) 5232ea8dc4b6Seschrock return (error); 5233ea8dc4b6Seschrock 5234e0f1c0afSOlaf Faaland /* 5235e0f1c0afSOlaf Faaland * If multihost is enabled, resuming I/O is unsafe as another 5236e0f1c0afSOlaf Faaland * host may have imported the pool. 5237e0f1c0afSOlaf Faaland */ 5238e0f1c0afSOlaf Faaland if (spa_multihost(spa) && spa_suspended(spa)) 5239e0f1c0afSOlaf Faaland return (SET_ERROR(EINVAL)); 5240e0f1c0afSOlaf Faaland 52418f18d1faSGeorge Wilson spa_vdev_state_enter(spa, SCL_NONE); 5242ea8dc4b6Seschrock 5243e9dbad6fSeschrock if (zc->zc_guid == 0) { 5244ea8dc4b6Seschrock vd = NULL; 5245c5904d13Seschrock } else { 5246c5904d13Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 5247fa94a07fSbrendan if (vd == NULL) { 5248e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, ENODEV); 5249fa94a07fSbrendan spa_close(spa, FTAG); 5250be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 5251fa94a07fSbrendan } 5252ea8dc4b6Seschrock } 5253ea8dc4b6Seschrock 5254e14bb325SJeff Bonwick vdev_clear(spa, vd); 5255e14bb325SJeff Bonwick 5256e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, 0); 5257ea8dc4b6Seschrock 5258e14bb325SJeff Bonwick /* 5259e14bb325SJeff Bonwick * Resume any suspended I/Os. 5260e14bb325SJeff Bonwick */ 526154d692b7SGeorge Wilson if (zio_resume(spa) != 0) 5262be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 5263ea8dc4b6Seschrock 5264ea8dc4b6Seschrock spa_close(spa, FTAG); 5265ea8dc4b6Seschrock 526654d692b7SGeorge Wilson return (error); 5267ea8dc4b6Seschrock } 5268ea8dc4b6Seschrock 52694263d13fSGeorge Wilson static int 52704263d13fSGeorge Wilson zfs_ioc_pool_reopen(zfs_cmd_t *zc) 52714263d13fSGeorge Wilson { 52724263d13fSGeorge Wilson spa_t *spa; 52734263d13fSGeorge Wilson int error; 52744263d13fSGeorge Wilson 52754263d13fSGeorge Wilson error = spa_open(zc->zc_name, &spa, FTAG); 52763b2aab18SMatthew Ahrens if (error != 0) 52774263d13fSGeorge Wilson return (error); 52784263d13fSGeorge Wilson 52794263d13fSGeorge Wilson spa_vdev_state_enter(spa, SCL_NONE); 5280d6afdce2SGeorge Wilson 5281d6afdce2SGeorge Wilson /* 5282d6afdce2SGeorge Wilson * If a resilver is already in progress then set the 5283d6afdce2SGeorge Wilson * spa_scrub_reopen flag to B_TRUE so that we don't restart 5284d6afdce2SGeorge Wilson * the scan as a side effect of the reopen. Otherwise, let 5285d6afdce2SGeorge Wilson * vdev_open() decided if a resilver is required. 5286d6afdce2SGeorge Wilson */ 5287d6afdce2SGeorge Wilson spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool); 52884263d13fSGeorge Wilson vdev_reopen(spa->spa_root_vdev); 5289d6afdce2SGeorge Wilson spa->spa_scrub_reopen = B_FALSE; 5290d6afdce2SGeorge Wilson 52914263d13fSGeorge Wilson (void) spa_vdev_state_exit(spa, NULL, 0); 52924263d13fSGeorge Wilson spa_close(spa, FTAG); 52934263d13fSGeorge Wilson return (0); 52944263d13fSGeorge Wilson } 52953cb34c60Sahrens /* 52963cb34c60Sahrens * inputs: 52973cb34c60Sahrens * zc_name name of filesystem 52983cb34c60Sahrens * 5299681d9761SEric Taylor * outputs: 5300681d9761SEric Taylor * zc_string name of conflicting snapshot, if there is one 53013cb34c60Sahrens */ 530299653d4eSeschrock static int 530399653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 530499653d4eSeschrock { 5305a4b8c9aaSAndrew Stormont dsl_pool_t *dp; 5306a4b8c9aaSAndrew Stormont dsl_dataset_t *ds, *ods; 5307a4b8c9aaSAndrew Stormont char origin[ZFS_MAX_DATASET_NAME_LEN]; 53080b69c2f0Sahrens char *cp; 5309a4b8c9aaSAndrew Stormont int error; 5310a4b8c9aaSAndrew Stormont 5311add927f8Sloli zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 5312add927f8Sloli if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 || 5313add927f8Sloli strchr(zc->zc_name, '%')) 5314add927f8Sloli return (SET_ERROR(EINVAL)); 5315add927f8Sloli 5316a4b8c9aaSAndrew Stormont error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 5317a4b8c9aaSAndrew Stormont if (error != 0) 5318a4b8c9aaSAndrew Stormont return (error); 5319a4b8c9aaSAndrew Stormont 5320a4b8c9aaSAndrew Stormont error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds); 5321a4b8c9aaSAndrew Stormont if (error != 0) { 5322a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 5323a4b8c9aaSAndrew Stormont return (error); 5324a4b8c9aaSAndrew Stormont } 5325a4b8c9aaSAndrew Stormont 5326a4b8c9aaSAndrew Stormont if (!dsl_dir_is_clone(ds->ds_dir)) { 5327a4b8c9aaSAndrew Stormont dsl_dataset_rele(ds, FTAG); 5328a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 5329a4b8c9aaSAndrew Stormont return (SET_ERROR(EINVAL)); 5330a4b8c9aaSAndrew Stormont } 5331a4b8c9aaSAndrew Stormont 5332a4b8c9aaSAndrew Stormont error = dsl_dataset_hold_obj(dp, 5333a4b8c9aaSAndrew Stormont dsl_dir_phys(ds->ds_dir)->dd_origin_obj, FTAG, &ods); 5334a4b8c9aaSAndrew Stormont if (error != 0) { 5335a4b8c9aaSAndrew Stormont dsl_dataset_rele(ds, FTAG); 5336a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 5337a4b8c9aaSAndrew Stormont return (error); 5338a4b8c9aaSAndrew Stormont } 5339a4b8c9aaSAndrew Stormont 5340a4b8c9aaSAndrew Stormont dsl_dataset_name(ods, origin); 5341a4b8c9aaSAndrew Stormont dsl_dataset_rele(ods, FTAG); 5342a4b8c9aaSAndrew Stormont dsl_dataset_rele(ds, FTAG); 5343a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 53440b69c2f0Sahrens 53450b69c2f0Sahrens /* 53460b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 53470b69c2f0Sahrens * it's easier. 53480b69c2f0Sahrens */ 5349a4b8c9aaSAndrew Stormont cp = strchr(origin, '@'); 53500b69c2f0Sahrens if (cp) 53510b69c2f0Sahrens *cp = '\0'; 5352a4b8c9aaSAndrew Stormont (void) dmu_objset_find(origin, 53533b2aab18SMatthew Ahrens zfs_unmount_snap_cb, NULL, DS_FIND_SNAPSHOTS); 5354681d9761SEric Taylor return (dsl_dataset_promote(zc->zc_name, zc->zc_string)); 535599653d4eSeschrock } 535699653d4eSeschrock 535714843421SMatthew Ahrens /* 5358f67950b2SNasf-Fan * Retrieve a single {user|group|project}{used|quota}@... property. 535914843421SMatthew Ahrens * 536014843421SMatthew Ahrens * inputs: 536114843421SMatthew Ahrens * zc_name name of filesystem 536214843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 536314843421SMatthew Ahrens * zc_value domain name (eg. "S-1-234-567-89") 536414843421SMatthew Ahrens * zc_guid RID/UID/GID 536514843421SMatthew Ahrens * 536614843421SMatthew Ahrens * outputs: 536714843421SMatthew Ahrens * zc_cookie property value 536814843421SMatthew Ahrens */ 536914843421SMatthew Ahrens static int 537014843421SMatthew Ahrens zfs_ioc_userspace_one(zfs_cmd_t *zc) 537114843421SMatthew Ahrens { 537214843421SMatthew Ahrens zfsvfs_t *zfsvfs; 537314843421SMatthew Ahrens int error; 537414843421SMatthew Ahrens 537514843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 5376be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 537714843421SMatthew Ahrens 53781412a1a2SMark Shellenbaum error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 53793b2aab18SMatthew Ahrens if (error != 0) 538014843421SMatthew Ahrens return (error); 538114843421SMatthew Ahrens 538214843421SMatthew Ahrens error = zfs_userspace_one(zfsvfs, 538314843421SMatthew Ahrens zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 538414843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 538514843421SMatthew Ahrens 538614843421SMatthew Ahrens return (error); 538714843421SMatthew Ahrens } 538814843421SMatthew Ahrens 538914843421SMatthew Ahrens /* 539014843421SMatthew Ahrens * inputs: 539114843421SMatthew Ahrens * zc_name name of filesystem 539214843421SMatthew Ahrens * zc_cookie zap cursor 539314843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 539414843421SMatthew Ahrens * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 539514843421SMatthew Ahrens * 539614843421SMatthew Ahrens * outputs: 539714843421SMatthew Ahrens * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 539814843421SMatthew Ahrens * zc_cookie zap cursor 539914843421SMatthew Ahrens */ 540014843421SMatthew Ahrens static int 540114843421SMatthew Ahrens zfs_ioc_userspace_many(zfs_cmd_t *zc) 540214843421SMatthew Ahrens { 540314843421SMatthew Ahrens zfsvfs_t *zfsvfs; 5404eeb85002STim Haley int bufsize = zc->zc_nvlist_dst_size; 540514843421SMatthew Ahrens 5406eeb85002STim Haley if (bufsize <= 0) 5407be6fd75aSMatthew Ahrens return (SET_ERROR(ENOMEM)); 5408eeb85002STim Haley 54091412a1a2SMark Shellenbaum int error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 54103b2aab18SMatthew Ahrens if (error != 0) 541114843421SMatthew Ahrens return (error); 541214843421SMatthew Ahrens 541314843421SMatthew Ahrens void *buf = kmem_alloc(bufsize, KM_SLEEP); 541414843421SMatthew Ahrens 541514843421SMatthew Ahrens error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 541614843421SMatthew Ahrens buf, &zc->zc_nvlist_dst_size); 541714843421SMatthew Ahrens 541814843421SMatthew Ahrens if (error == 0) { 541914843421SMatthew Ahrens error = xcopyout(buf, 542014843421SMatthew Ahrens (void *)(uintptr_t)zc->zc_nvlist_dst, 542114843421SMatthew Ahrens zc->zc_nvlist_dst_size); 542214843421SMatthew Ahrens } 542314843421SMatthew Ahrens kmem_free(buf, bufsize); 542414843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 542514843421SMatthew Ahrens 542614843421SMatthew Ahrens return (error); 542714843421SMatthew Ahrens } 542814843421SMatthew Ahrens 542914843421SMatthew Ahrens /* 543014843421SMatthew Ahrens * inputs: 543114843421SMatthew Ahrens * zc_name name of filesystem 543214843421SMatthew Ahrens * 543314843421SMatthew Ahrens * outputs: 543414843421SMatthew Ahrens * none 543514843421SMatthew Ahrens */ 543614843421SMatthew Ahrens static int 543714843421SMatthew Ahrens zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 543814843421SMatthew Ahrens { 543914843421SMatthew Ahrens objset_t *os; 54401195e687SMark J Musante int error = 0; 544114843421SMatthew Ahrens zfsvfs_t *zfsvfs; 544214843421SMatthew Ahrens 544314843421SMatthew Ahrens if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 5444503ad85cSMatthew Ahrens if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { 544514843421SMatthew Ahrens /* 544614843421SMatthew Ahrens * If userused is not enabled, it may be because the 544714843421SMatthew Ahrens * objset needs to be closed & reopened (to grow the 544814843421SMatthew Ahrens * objset_phys_t). Suspend/resume the fs will do that. 544914843421SMatthew Ahrens */ 54505f5913bbSAndriy Gapon dsl_dataset_t *ds, *newds; 5451690041b9SAndriy Gapon 5452690041b9SAndriy Gapon ds = dmu_objset_ds(zfsvfs->z_os); 5453503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 545491948b51SKeith M Wesolowski if (error == 0) { 54555f5913bbSAndriy Gapon dmu_objset_refresh_ownership(ds, &newds, 5456eb633035STom Caputi B_TRUE, zfsvfs); 54575f5913bbSAndriy Gapon error = zfs_resume_fs(zfsvfs, newds); 545891948b51SKeith M Wesolowski } 545914843421SMatthew Ahrens } 546014843421SMatthew Ahrens if (error == 0) 546114843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 546214843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 546314843421SMatthew Ahrens } else { 5464503ad85cSMatthew Ahrens /* XXX kind of reading contents without owning */ 5465eb633035STom Caputi error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, FTAG, &os); 54663b2aab18SMatthew Ahrens if (error != 0) 546714843421SMatthew Ahrens return (error); 546814843421SMatthew Ahrens 546914843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(os); 5470eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 547114843421SMatthew Ahrens } 547214843421SMatthew Ahrens 547314843421SMatthew Ahrens return (error); 547414843421SMatthew Ahrens } 547514843421SMatthew Ahrens 5476f67950b2SNasf-Fan /* 5477f67950b2SNasf-Fan * inputs: 5478f67950b2SNasf-Fan * zc_name name of filesystem 5479f67950b2SNasf-Fan * 5480f67950b2SNasf-Fan * outputs: 5481f67950b2SNasf-Fan * none 5482f67950b2SNasf-Fan */ 5483f67950b2SNasf-Fan static int 5484f67950b2SNasf-Fan zfs_ioc_id_quota_upgrade(zfs_cmd_t *zc) 5485f67950b2SNasf-Fan { 5486f67950b2SNasf-Fan objset_t *os; 5487f67950b2SNasf-Fan int error; 5488f67950b2SNasf-Fan 5489f67950b2SNasf-Fan error = dmu_objset_hold(zc->zc_name, FTAG, &os); 5490f67950b2SNasf-Fan if (error != 0) 5491f67950b2SNasf-Fan return (error); 5492f67950b2SNasf-Fan 5493f67950b2SNasf-Fan dsl_dataset_long_hold(dmu_objset_ds(os), FTAG); 5494f67950b2SNasf-Fan dsl_pool_rele(dmu_objset_pool(os), FTAG); 5495f67950b2SNasf-Fan 5496f67950b2SNasf-Fan if (dmu_objset_userobjspace_upgradable(os) || 5497f67950b2SNasf-Fan dmu_objset_projectquota_upgradable(os)) { 5498f67950b2SNasf-Fan mutex_enter(&os->os_upgrade_lock); 5499f67950b2SNasf-Fan if (os->os_upgrade_id == 0) { 5500f67950b2SNasf-Fan /* clear potential error code and retry */ 5501f67950b2SNasf-Fan os->os_upgrade_status = 0; 5502f67950b2SNasf-Fan mutex_exit(&os->os_upgrade_lock); 5503f67950b2SNasf-Fan 5504f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(os); 5505f67950b2SNasf-Fan } else { 5506f67950b2SNasf-Fan mutex_exit(&os->os_upgrade_lock); 5507f67950b2SNasf-Fan } 5508f67950b2SNasf-Fan 5509f67950b2SNasf-Fan taskq_wait_id(os->os_spa->spa_upgrade_taskq, os->os_upgrade_id); 5510f67950b2SNasf-Fan error = os->os_upgrade_status; 5511f67950b2SNasf-Fan } 5512f67950b2SNasf-Fan 5513f67950b2SNasf-Fan dsl_dataset_long_rele(dmu_objset_ds(os), FTAG); 5514f67950b2SNasf-Fan dsl_dataset_rele(dmu_objset_ds(os), FTAG); 5515f67950b2SNasf-Fan 5516f67950b2SNasf-Fan return (error); 5517f67950b2SNasf-Fan } 5518f67950b2SNasf-Fan 5519ecd6cf80Smarks /* 5520ecd6cf80Smarks * We don't want to have a hard dependency 5521ecd6cf80Smarks * against some special symbols in sharefs 5522da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 5523ecd6cf80Smarks * the first file system is shared. 5524da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 5525ecd6cf80Smarks */ 5526da6c28aaSamw int (*znfsexport_fs)(void *arg); 5527ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 5528da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 5529da6c28aaSamw 5530da6c28aaSamw int zfs_nfsshare_inited; 5531da6c28aaSamw int zfs_smbshare_inited; 5532ecd6cf80Smarks 5533ecd6cf80Smarks ddi_modhandle_t nfs_mod; 5534ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 5535da6c28aaSamw ddi_modhandle_t smbsrv_mod; 5536ecd6cf80Smarks kmutex_t zfs_share_lock; 5537ecd6cf80Smarks 5538da6c28aaSamw static int 5539da6c28aaSamw zfs_init_sharefs() 5540da6c28aaSamw { 5541da6c28aaSamw int error; 5542da6c28aaSamw 5543da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 5544da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 5545da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 5546da6c28aaSamw ddi_modopen("fs/sharefs", 5547da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 5548be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5549da6c28aaSamw } 5550da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 5551da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 5552da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 5553be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5554da6c28aaSamw } 5555da6c28aaSamw return (0); 5556da6c28aaSamw } 5557da6c28aaSamw 5558ecd6cf80Smarks static int 5559ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 5560ecd6cf80Smarks { 5561ecd6cf80Smarks int error; 5562ecd6cf80Smarks int opcode; 5563ecd6cf80Smarks 5564da6c28aaSamw switch (zc->zc_share.z_sharetype) { 5565da6c28aaSamw case ZFS_SHARE_NFS: 5566da6c28aaSamw case ZFS_UNSHARE_NFS: 5567da6c28aaSamw if (zfs_nfsshare_inited == 0) { 5568da6c28aaSamw mutex_enter(&zfs_share_lock); 5569da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 5570da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 5571da6c28aaSamw mutex_exit(&zfs_share_lock); 5572be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5573da6c28aaSamw } 5574da6c28aaSamw if (znfsexport_fs == NULL && 5575da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 5576da6c28aaSamw ddi_modsym(nfs_mod, 5577da6c28aaSamw "nfs_export", &error)) == NULL)) { 5578da6c28aaSamw mutex_exit(&zfs_share_lock); 5579be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5580da6c28aaSamw } 5581da6c28aaSamw error = zfs_init_sharefs(); 55823b2aab18SMatthew Ahrens if (error != 0) { 5583da6c28aaSamw mutex_exit(&zfs_share_lock); 5584be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5585da6c28aaSamw } 5586da6c28aaSamw zfs_nfsshare_inited = 1; 5587ecd6cf80Smarks mutex_exit(&zfs_share_lock); 5588ecd6cf80Smarks } 5589da6c28aaSamw break; 5590da6c28aaSamw case ZFS_SHARE_SMB: 5591da6c28aaSamw case ZFS_UNSHARE_SMB: 5592da6c28aaSamw if (zfs_smbshare_inited == 0) { 5593da6c28aaSamw mutex_enter(&zfs_share_lock); 5594da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 5595da6c28aaSamw ddi_modopen("drv/smbsrv", 5596da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 5597da6c28aaSamw mutex_exit(&zfs_share_lock); 5598be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5599da6c28aaSamw } 5600da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 5601da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 5602faa1795aSjb "smb_server_share", &error)) == NULL)) { 5603da6c28aaSamw mutex_exit(&zfs_share_lock); 5604be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5605da6c28aaSamw } 5606da6c28aaSamw error = zfs_init_sharefs(); 56073b2aab18SMatthew Ahrens if (error != 0) { 5608da6c28aaSamw mutex_exit(&zfs_share_lock); 5609be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5610da6c28aaSamw } 5611da6c28aaSamw zfs_smbshare_inited = 1; 5612ecd6cf80Smarks mutex_exit(&zfs_share_lock); 5613ecd6cf80Smarks } 5614da6c28aaSamw break; 5615da6c28aaSamw default: 5616be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5617da6c28aaSamw } 5618ecd6cf80Smarks 5619da6c28aaSamw switch (zc->zc_share.z_sharetype) { 5620da6c28aaSamw case ZFS_SHARE_NFS: 5621da6c28aaSamw case ZFS_UNSHARE_NFS: 5622da6c28aaSamw if (error = 5623da6c28aaSamw znfsexport_fs((void *) 5624da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 5625da6c28aaSamw return (error); 5626da6c28aaSamw break; 5627da6c28aaSamw case ZFS_SHARE_SMB: 5628da6c28aaSamw case ZFS_UNSHARE_SMB: 5629da6c28aaSamw if (error = zsmbexport_fs((void *) 5630da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 5631da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 5632743a77edSAlan Wright B_TRUE: B_FALSE)) { 5633da6c28aaSamw return (error); 5634ecd6cf80Smarks } 5635da6c28aaSamw break; 5636ecd6cf80Smarks } 5637ecd6cf80Smarks 5638da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 5639da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 5640ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 5641ecd6cf80Smarks 5642da6c28aaSamw /* 5643da6c28aaSamw * Add or remove share from sharetab 5644da6c28aaSamw */ 5645ecd6cf80Smarks error = zshare_fs(opcode, 5646ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 5647ecd6cf80Smarks zc->zc_share.z_sharemax); 5648ecd6cf80Smarks 5649ecd6cf80Smarks return (error); 5650ecd6cf80Smarks 5651ecd6cf80Smarks } 5652ecd6cf80Smarks 5653743a77edSAlan Wright ace_t full_access[] = { 5654743a77edSAlan Wright {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 5655743a77edSAlan Wright }; 5656743a77edSAlan Wright 565799d5e173STim Haley /* 565899d5e173STim Haley * inputs: 565999d5e173STim Haley * zc_name name of containing filesystem 566099d5e173STim Haley * zc_obj object # beyond which we want next in-use object # 566199d5e173STim Haley * 566299d5e173STim Haley * outputs: 566399d5e173STim Haley * zc_obj next in-use object # 566499d5e173STim Haley */ 566599d5e173STim Haley static int 566699d5e173STim Haley zfs_ioc_next_obj(zfs_cmd_t *zc) 566799d5e173STim Haley { 566899d5e173STim Haley objset_t *os = NULL; 566999d5e173STim Haley int error; 567099d5e173STim Haley 5671eb633035STom Caputi error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, FTAG, &os); 56723b2aab18SMatthew Ahrens if (error != 0) 567399d5e173STim Haley return (error); 567499d5e173STim Haley 567599d5e173STim Haley error = dmu_object_next(os, &zc->zc_obj, B_FALSE, 5676c1379625SJustin T. Gibbs dsl_dataset_phys(os->os_dsl_dataset)->ds_prev_snap_txg); 567799d5e173STim Haley 567899d5e173STim Haley dmu_objset_rele(os, FTAG); 567999d5e173STim Haley return (error); 568099d5e173STim Haley } 568199d5e173STim Haley 568299d5e173STim Haley /* 568399d5e173STim Haley * inputs: 568499d5e173STim Haley * zc_name name of filesystem 568599d5e173STim Haley * zc_value prefix name for snapshot 568699d5e173STim Haley * zc_cleanup_fd cleanup-on-exit file descriptor for calling process 568799d5e173STim Haley * 568899d5e173STim Haley * outputs: 56894445fffbSMatthew Ahrens * zc_value short name of new snapshot 569099d5e173STim Haley */ 569199d5e173STim Haley static int 569299d5e173STim Haley zfs_ioc_tmp_snapshot(zfs_cmd_t *zc) 569399d5e173STim Haley { 569499d5e173STim Haley char *snap_name; 56953b2aab18SMatthew Ahrens char *hold_name; 569699d5e173STim Haley int error; 56973b2aab18SMatthew Ahrens minor_t minor; 569899d5e173STim Haley 56993b2aab18SMatthew Ahrens error = zfs_onexit_fd_hold(zc->zc_cleanup_fd, &minor); 57003b2aab18SMatthew Ahrens if (error != 0) 570199d5e173STim Haley return (error); 570299d5e173STim Haley 57033b2aab18SMatthew Ahrens snap_name = kmem_asprintf("%s-%016llx", zc->zc_value, 57043b2aab18SMatthew Ahrens (u_longlong_t)ddi_get_lbolt64()); 57053b2aab18SMatthew Ahrens hold_name = kmem_asprintf("%%%s", zc->zc_value); 57063b2aab18SMatthew Ahrens 57073b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_tmp(zc->zc_name, snap_name, minor, 57083b2aab18SMatthew Ahrens hold_name); 57093b2aab18SMatthew Ahrens if (error == 0) 57103b2aab18SMatthew Ahrens (void) strcpy(zc->zc_value, snap_name); 571199d5e173STim Haley strfree(snap_name); 57123b2aab18SMatthew Ahrens strfree(hold_name); 57133b2aab18SMatthew Ahrens zfs_onexit_fd_rele(zc->zc_cleanup_fd); 57143b2aab18SMatthew Ahrens return (error); 571599d5e173STim Haley } 571699d5e173STim Haley 571799d5e173STim Haley /* 571899d5e173STim Haley * inputs: 571999d5e173STim Haley * zc_name name of "to" snapshot 572099d5e173STim Haley * zc_value name of "from" snapshot 572199d5e173STim Haley * zc_cookie file descriptor to write diff data on 572299d5e173STim Haley * 572399d5e173STim Haley * outputs: 572499d5e173STim Haley * dmu_diff_record_t's to the file descriptor 572599d5e173STim Haley */ 572699d5e173STim Haley static int 572799d5e173STim Haley zfs_ioc_diff(zfs_cmd_t *zc) 572899d5e173STim Haley { 572999d5e173STim Haley file_t *fp; 573099d5e173STim Haley offset_t off; 573199d5e173STim Haley int error; 573299d5e173STim Haley 573399d5e173STim Haley fp = getf(zc->zc_cookie); 57343b2aab18SMatthew Ahrens if (fp == NULL) 5735be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 573699d5e173STim Haley 573799d5e173STim Haley off = fp->f_offset; 573899d5e173STim Haley 57393b2aab18SMatthew Ahrens error = dmu_diff(zc->zc_name, zc->zc_value, fp->f_vnode, &off); 574099d5e173STim Haley 574199d5e173STim Haley if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 574299d5e173STim Haley fp->f_offset = off; 574399d5e173STim Haley releasef(zc->zc_cookie); 574499d5e173STim Haley 574599d5e173STim Haley return (error); 574699d5e173STim Haley } 574799d5e173STim Haley 5748743a77edSAlan Wright /* 5749743a77edSAlan Wright * Remove all ACL files in shares dir 5750743a77edSAlan Wright */ 5751743a77edSAlan Wright static int 5752743a77edSAlan Wright zfs_smb_acl_purge(znode_t *dzp) 5753743a77edSAlan Wright { 5754743a77edSAlan Wright zap_cursor_t zc; 5755743a77edSAlan Wright zap_attribute_t zap; 5756743a77edSAlan Wright zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 5757743a77edSAlan Wright int error; 5758743a77edSAlan Wright 5759743a77edSAlan Wright for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 5760743a77edSAlan Wright (error = zap_cursor_retrieve(&zc, &zap)) == 0; 5761743a77edSAlan Wright zap_cursor_advance(&zc)) { 5762743a77edSAlan Wright if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 5763743a77edSAlan Wright NULL, 0)) != 0) 5764743a77edSAlan Wright break; 5765743a77edSAlan Wright } 5766743a77edSAlan Wright zap_cursor_fini(&zc); 5767743a77edSAlan Wright return (error); 5768743a77edSAlan Wright } 5769743a77edSAlan Wright 5770743a77edSAlan Wright static int 5771743a77edSAlan Wright zfs_ioc_smb_acl(zfs_cmd_t *zc) 5772743a77edSAlan Wright { 5773743a77edSAlan Wright vnode_t *vp; 5774743a77edSAlan Wright znode_t *dzp; 5775743a77edSAlan Wright vnode_t *resourcevp = NULL; 5776743a77edSAlan Wright znode_t *sharedir; 5777743a77edSAlan Wright zfsvfs_t *zfsvfs; 5778743a77edSAlan Wright nvlist_t *nvlist; 5779743a77edSAlan Wright char *src, *target; 5780743a77edSAlan Wright vattr_t vattr; 5781743a77edSAlan Wright vsecattr_t vsec; 5782743a77edSAlan Wright int error = 0; 5783743a77edSAlan Wright 5784743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 5785743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 5786743a77edSAlan Wright return (error); 5787743a77edSAlan Wright 5788743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 5789743a77edSAlan Wright 5790743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 5791743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 5792743a77edSAlan Wright zc->zc_name) != 0)) { 5793743a77edSAlan Wright VN_RELE(vp); 5794be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5795743a77edSAlan Wright } 5796743a77edSAlan Wright 5797743a77edSAlan Wright dzp = VTOZ(vp); 5798743a77edSAlan Wright zfsvfs = dzp->z_zfsvfs; 5799743a77edSAlan Wright ZFS_ENTER(zfsvfs); 5800743a77edSAlan Wright 58019e1320c0SMark Shellenbaum /* 58029e1320c0SMark Shellenbaum * Create share dir if its missing. 58039e1320c0SMark Shellenbaum */ 58049e1320c0SMark Shellenbaum mutex_enter(&zfsvfs->z_lock); 58059e1320c0SMark Shellenbaum if (zfsvfs->z_shares_dir == 0) { 58069e1320c0SMark Shellenbaum dmu_tx_t *tx; 58079e1320c0SMark Shellenbaum 58089e1320c0SMark Shellenbaum tx = dmu_tx_create(zfsvfs->z_os); 58099e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 58109e1320c0SMark Shellenbaum ZFS_SHARES_DIR); 58119e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 58129e1320c0SMark Shellenbaum error = dmu_tx_assign(tx, TXG_WAIT); 58133b2aab18SMatthew Ahrens if (error != 0) { 58149e1320c0SMark Shellenbaum dmu_tx_abort(tx); 58159e1320c0SMark Shellenbaum } else { 58169e1320c0SMark Shellenbaum error = zfs_create_share_dir(zfsvfs, tx); 58179e1320c0SMark Shellenbaum dmu_tx_commit(tx); 58189e1320c0SMark Shellenbaum } 58193b2aab18SMatthew Ahrens if (error != 0) { 58209e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 58219e1320c0SMark Shellenbaum VN_RELE(vp); 58229e1320c0SMark Shellenbaum ZFS_EXIT(zfsvfs); 58239e1320c0SMark Shellenbaum return (error); 58249e1320c0SMark Shellenbaum } 58259e1320c0SMark Shellenbaum } 58269e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 58279e1320c0SMark Shellenbaum 58289e1320c0SMark Shellenbaum ASSERT(zfsvfs->z_shares_dir); 5829743a77edSAlan Wright if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 58309e1320c0SMark Shellenbaum VN_RELE(vp); 5831743a77edSAlan Wright ZFS_EXIT(zfsvfs); 5832743a77edSAlan Wright return (error); 5833743a77edSAlan Wright } 5834743a77edSAlan Wright 5835743a77edSAlan Wright switch (zc->zc_cookie) { 5836743a77edSAlan Wright case ZFS_SMB_ACL_ADD: 5837743a77edSAlan Wright vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 5838743a77edSAlan Wright vattr.va_type = VREG; 5839743a77edSAlan Wright vattr.va_mode = S_IFREG|0777; 5840743a77edSAlan Wright vattr.va_uid = 0; 5841743a77edSAlan Wright vattr.va_gid = 0; 5842743a77edSAlan Wright 5843743a77edSAlan Wright vsec.vsa_mask = VSA_ACE; 5844743a77edSAlan Wright vsec.vsa_aclentp = &full_access; 5845743a77edSAlan Wright vsec.vsa_aclentsz = sizeof (full_access); 5846743a77edSAlan Wright vsec.vsa_aclcnt = 1; 5847743a77edSAlan Wright 5848743a77edSAlan Wright error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 5849743a77edSAlan Wright &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 5850743a77edSAlan Wright if (resourcevp) 5851743a77edSAlan Wright VN_RELE(resourcevp); 5852743a77edSAlan Wright break; 5853743a77edSAlan Wright 5854743a77edSAlan Wright case ZFS_SMB_ACL_REMOVE: 5855743a77edSAlan Wright error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 5856743a77edSAlan Wright NULL, 0); 5857743a77edSAlan Wright break; 5858743a77edSAlan Wright 5859743a77edSAlan Wright case ZFS_SMB_ACL_RENAME: 5860743a77edSAlan Wright if ((error = get_nvlist(zc->zc_nvlist_src, 5861478ed9adSEric Taylor zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { 5862743a77edSAlan Wright VN_RELE(vp); 58638f5190a5SDan McDonald VN_RELE(ZTOV(sharedir)); 5864743a77edSAlan Wright ZFS_EXIT(zfsvfs); 5865743a77edSAlan Wright return (error); 5866743a77edSAlan Wright } 5867743a77edSAlan Wright if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 5868743a77edSAlan Wright nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 5869743a77edSAlan Wright &target)) { 5870743a77edSAlan Wright VN_RELE(vp); 587189459e17SMark Shellenbaum VN_RELE(ZTOV(sharedir)); 5872743a77edSAlan Wright ZFS_EXIT(zfsvfs); 58731195e687SMark J Musante nvlist_free(nvlist); 5874743a77edSAlan Wright return (error); 5875743a77edSAlan Wright } 5876743a77edSAlan Wright error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 5877743a77edSAlan Wright kcred, NULL, 0); 5878743a77edSAlan Wright nvlist_free(nvlist); 5879743a77edSAlan Wright break; 5880743a77edSAlan Wright 5881743a77edSAlan Wright case ZFS_SMB_ACL_PURGE: 5882743a77edSAlan Wright error = zfs_smb_acl_purge(sharedir); 5883743a77edSAlan Wright break; 5884743a77edSAlan Wright 5885743a77edSAlan Wright default: 5886be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 5887743a77edSAlan Wright break; 5888743a77edSAlan Wright } 5889743a77edSAlan Wright 5890743a77edSAlan Wright VN_RELE(vp); 5891743a77edSAlan Wright VN_RELE(ZTOV(sharedir)); 5892743a77edSAlan Wright 5893743a77edSAlan Wright ZFS_EXIT(zfsvfs); 5894743a77edSAlan Wright 5895743a77edSAlan Wright return (error); 5896743a77edSAlan Wright } 5897743a77edSAlan Wright 5898842727c2SChris Kirby /* 58993b2aab18SMatthew Ahrens * innvl: { 59003b2aab18SMatthew Ahrens * "holds" -> { snapname -> holdname (string), ... } 59013b2aab18SMatthew Ahrens * (optional) "cleanup_fd" -> fd (int32) 59023b2aab18SMatthew Ahrens * } 5903842727c2SChris Kirby * 59043b2aab18SMatthew Ahrens * outnvl: { 59053b2aab18SMatthew Ahrens * snapname -> error value (int32) 59063b2aab18SMatthew Ahrens * ... 59073b2aab18SMatthew Ahrens * } 5908842727c2SChris Kirby */ 59093b2aab18SMatthew Ahrens /* ARGSUSED */ 5910842727c2SChris Kirby static int 59113b2aab18SMatthew Ahrens zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist) 5912842727c2SChris Kirby { 5913752fd8daSJosef 'Jeff' Sipek nvpair_t *pair; 59143b2aab18SMatthew Ahrens nvlist_t *holds; 59153b2aab18SMatthew Ahrens int cleanup_fd = -1; 5916a7f53a56SChris Kirby int error; 5917a7f53a56SChris Kirby minor_t minor = 0; 5918842727c2SChris Kirby 59193b2aab18SMatthew Ahrens error = nvlist_lookup_nvlist(args, "holds", &holds); 59203b2aab18SMatthew Ahrens if (error != 0) 5921be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5922a7f53a56SChris Kirby 5923752fd8daSJosef 'Jeff' Sipek /* make sure the user didn't pass us any invalid (empty) tags */ 5924752fd8daSJosef 'Jeff' Sipek for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; 5925752fd8daSJosef 'Jeff' Sipek pair = nvlist_next_nvpair(holds, pair)) { 5926752fd8daSJosef 'Jeff' Sipek char *htag; 5927752fd8daSJosef 'Jeff' Sipek 5928752fd8daSJosef 'Jeff' Sipek error = nvpair_value_string(pair, &htag); 5929752fd8daSJosef 'Jeff' Sipek if (error != 0) 5930752fd8daSJosef 'Jeff' Sipek return (SET_ERROR(error)); 5931752fd8daSJosef 'Jeff' Sipek 5932752fd8daSJosef 'Jeff' Sipek if (strlen(htag) == 0) 5933752fd8daSJosef 'Jeff' Sipek return (SET_ERROR(EINVAL)); 5934752fd8daSJosef 'Jeff' Sipek } 5935752fd8daSJosef 'Jeff' Sipek 59363b2aab18SMatthew Ahrens if (nvlist_lookup_int32(args, "cleanup_fd", &cleanup_fd) == 0) { 59373b2aab18SMatthew Ahrens error = zfs_onexit_fd_hold(cleanup_fd, &minor); 59383b2aab18SMatthew Ahrens if (error != 0) 5939a7f53a56SChris Kirby return (error); 5940a7f53a56SChris Kirby } 5941a7f53a56SChris Kirby 59423b2aab18SMatthew Ahrens error = dsl_dataset_user_hold(holds, minor, errlist); 59433b2aab18SMatthew Ahrens if (minor != 0) 59443b2aab18SMatthew Ahrens zfs_onexit_fd_rele(cleanup_fd); 5945a7f53a56SChris Kirby return (error); 5946842727c2SChris Kirby } 5947842727c2SChris Kirby 5948842727c2SChris Kirby /* 59493b2aab18SMatthew Ahrens * innvl is not used. 5950842727c2SChris Kirby * 59513b2aab18SMatthew Ahrens * outnvl: { 59523b2aab18SMatthew Ahrens * holdname -> time added (uint64 seconds since epoch) 59533b2aab18SMatthew Ahrens * ... 59543b2aab18SMatthew Ahrens * } 5955842727c2SChris Kirby */ 59563b2aab18SMatthew Ahrens /* ARGSUSED */ 5957842727c2SChris Kirby static int 59583b2aab18SMatthew Ahrens zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl) 5959842727c2SChris Kirby { 59609c2acf00SAlek Pinchuk ASSERT3P(args, ==, NULL); 59613b2aab18SMatthew Ahrens return (dsl_dataset_get_holds(snapname, outnvl)); 5962842727c2SChris Kirby } 5963842727c2SChris Kirby 5964842727c2SChris Kirby /* 59653b2aab18SMatthew Ahrens * innvl: { 59663b2aab18SMatthew Ahrens * snapname -> { holdname, ... } 59673b2aab18SMatthew Ahrens * ... 59683b2aab18SMatthew Ahrens * } 5969842727c2SChris Kirby * 59703b2aab18SMatthew Ahrens * outnvl: { 59713b2aab18SMatthew Ahrens * snapname -> error value (int32) 59723b2aab18SMatthew Ahrens * ... 59733b2aab18SMatthew Ahrens * } 5974842727c2SChris Kirby */ 59753b2aab18SMatthew Ahrens /* ARGSUSED */ 5976842727c2SChris Kirby static int 59773b2aab18SMatthew Ahrens zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist) 5978842727c2SChris Kirby { 59793b2aab18SMatthew Ahrens return (dsl_dataset_user_release(holds, errlist)); 5980842727c2SChris Kirby } 5981842727c2SChris Kirby 598219b94df9SMatthew Ahrens /* 598319b94df9SMatthew Ahrens * inputs: 598419b94df9SMatthew Ahrens * zc_name name of new filesystem or snapshot 598519b94df9SMatthew Ahrens * zc_value full name of old snapshot 598619b94df9SMatthew Ahrens * 598719b94df9SMatthew Ahrens * outputs: 598819b94df9SMatthew Ahrens * zc_cookie space in bytes 598919b94df9SMatthew Ahrens * zc_objset_type compressed space in bytes 599019b94df9SMatthew Ahrens * zc_perm_action uncompressed space in bytes 599119b94df9SMatthew Ahrens */ 599219b94df9SMatthew Ahrens static int 599319b94df9SMatthew Ahrens zfs_ioc_space_written(zfs_cmd_t *zc) 599419b94df9SMatthew Ahrens { 599519b94df9SMatthew Ahrens int error; 59963b2aab18SMatthew Ahrens dsl_pool_t *dp; 599719b94df9SMatthew Ahrens dsl_dataset_t *new, *old; 599819b94df9SMatthew Ahrens 59993b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 600019b94df9SMatthew Ahrens if (error != 0) 600119b94df9SMatthew Ahrens return (error); 60023b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &new); 60033b2aab18SMatthew Ahrens if (error != 0) { 60043b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 60053b2aab18SMatthew Ahrens return (error); 60063b2aab18SMatthew Ahrens } 60073b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_value, FTAG, &old); 600819b94df9SMatthew Ahrens if (error != 0) { 600919b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 60103b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 601119b94df9SMatthew Ahrens return (error); 601219b94df9SMatthew Ahrens } 601319b94df9SMatthew Ahrens 601419b94df9SMatthew Ahrens error = dsl_dataset_space_written(old, new, &zc->zc_cookie, 601519b94df9SMatthew Ahrens &zc->zc_objset_type, &zc->zc_perm_action); 601619b94df9SMatthew Ahrens dsl_dataset_rele(old, FTAG); 601719b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 60183b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 601919b94df9SMatthew Ahrens return (error); 602019b94df9SMatthew Ahrens } 60213b2aab18SMatthew Ahrens 602219b94df9SMatthew Ahrens /* 60234445fffbSMatthew Ahrens * innvl: { 60244445fffbSMatthew Ahrens * "firstsnap" -> snapshot name 60254445fffbSMatthew Ahrens * } 602619b94df9SMatthew Ahrens * 60274445fffbSMatthew Ahrens * outnvl: { 60284445fffbSMatthew Ahrens * "used" -> space in bytes 60294445fffbSMatthew Ahrens * "compressed" -> compressed space in bytes 60304445fffbSMatthew Ahrens * "uncompressed" -> uncompressed space in bytes 60314445fffbSMatthew Ahrens * } 603219b94df9SMatthew Ahrens */ 603319b94df9SMatthew Ahrens static int 60344445fffbSMatthew Ahrens zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl) 603519b94df9SMatthew Ahrens { 603619b94df9SMatthew Ahrens int error; 60373b2aab18SMatthew Ahrens dsl_pool_t *dp; 603819b94df9SMatthew Ahrens dsl_dataset_t *new, *old; 60394445fffbSMatthew Ahrens char *firstsnap; 60404445fffbSMatthew Ahrens uint64_t used, comp, uncomp; 604119b94df9SMatthew Ahrens 60424445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "firstsnap", &firstsnap) != 0) 6043be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 60444445fffbSMatthew Ahrens 60453b2aab18SMatthew Ahrens error = dsl_pool_hold(lastsnap, FTAG, &dp); 604619b94df9SMatthew Ahrens if (error != 0) 604719b94df9SMatthew Ahrens return (error); 60483b2aab18SMatthew Ahrens 60493b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, lastsnap, FTAG, &new); 605024218bebSAndriy Gapon if (error == 0 && !new->ds_is_snapshot) { 605124218bebSAndriy Gapon dsl_dataset_rele(new, FTAG); 605224218bebSAndriy Gapon error = SET_ERROR(EINVAL); 605324218bebSAndriy Gapon } 60543b2aab18SMatthew Ahrens if (error != 0) { 60553b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 60563b2aab18SMatthew Ahrens return (error); 60573b2aab18SMatthew Ahrens } 60583b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, firstsnap, FTAG, &old); 605924218bebSAndriy Gapon if (error == 0 && !old->ds_is_snapshot) { 606024218bebSAndriy Gapon dsl_dataset_rele(old, FTAG); 606124218bebSAndriy Gapon error = SET_ERROR(EINVAL); 606224218bebSAndriy Gapon } 606319b94df9SMatthew Ahrens if (error != 0) { 606419b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 60653b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 606619b94df9SMatthew Ahrens return (error); 606719b94df9SMatthew Ahrens } 606819b94df9SMatthew Ahrens 60694445fffbSMatthew Ahrens error = dsl_dataset_space_wouldfree(old, new, &used, &comp, &uncomp); 607019b94df9SMatthew Ahrens dsl_dataset_rele(old, FTAG); 607119b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 60723b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 60734445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "used", used); 60744445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "compressed", comp); 60754445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "uncompressed", uncomp); 607619b94df9SMatthew Ahrens return (error); 607719b94df9SMatthew Ahrens } 607819b94df9SMatthew Ahrens 6079ecd6cf80Smarks /* 60804445fffbSMatthew Ahrens * innvl: { 60814445fffbSMatthew Ahrens * "fd" -> file descriptor to write stream to (int32) 60824445fffbSMatthew Ahrens * (optional) "fromsnap" -> full snap name to send an incremental from 6083b5152584SMatthew Ahrens * (optional) "largeblockok" -> (value ignored) 6084b5152584SMatthew Ahrens * indicates that blocks > 128KB are permitted 60855d7b4d43SMatthew Ahrens * (optional) "embedok" -> (value ignored) 60865d7b4d43SMatthew Ahrens * presence indicates DRR_WRITE_EMBEDDED records are permitted 60875602294fSDan Kimmel * (optional) "compressok" -> (value ignored) 60885602294fSDan Kimmel * presence indicates compressed DRR_WRITE records are permitted 6089eb633035STom Caputi * (optional) "rawok" -> (value ignored) 6090eb633035STom Caputi * presence indicates raw encrypted records should be used. 60919c3fd121SMatthew Ahrens * (optional) "resume_object" and "resume_offset" -> (uint64) 60929c3fd121SMatthew Ahrens * if present, resume send stream from specified object and offset. 60934445fffbSMatthew Ahrens * } 60944445fffbSMatthew Ahrens * 60954445fffbSMatthew Ahrens * outnvl is unused 6096ecd6cf80Smarks */ 60974445fffbSMatthew Ahrens /* ARGSUSED */ 60984445fffbSMatthew Ahrens static int 60994445fffbSMatthew Ahrens zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) 61004445fffbSMatthew Ahrens { 61014445fffbSMatthew Ahrens int error; 61024445fffbSMatthew Ahrens offset_t off; 61033b2aab18SMatthew Ahrens char *fromname = NULL; 61044445fffbSMatthew Ahrens int fd; 6105b5152584SMatthew Ahrens boolean_t largeblockok; 61065d7b4d43SMatthew Ahrens boolean_t embedok; 61075602294fSDan Kimmel boolean_t compressok; 6108eb633035STom Caputi boolean_t rawok; 61099c3fd121SMatthew Ahrens uint64_t resumeobj = 0; 61109c3fd121SMatthew Ahrens uint64_t resumeoff = 0; 61114445fffbSMatthew Ahrens 61124445fffbSMatthew Ahrens error = nvlist_lookup_int32(innvl, "fd", &fd); 61134445fffbSMatthew Ahrens if (error != 0) 6114be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 61154445fffbSMatthew Ahrens 61163b2aab18SMatthew Ahrens (void) nvlist_lookup_string(innvl, "fromsnap", &fromname); 61174445fffbSMatthew Ahrens 6118b5152584SMatthew Ahrens largeblockok = nvlist_exists(innvl, "largeblockok"); 61195d7b4d43SMatthew Ahrens embedok = nvlist_exists(innvl, "embedok"); 61205602294fSDan Kimmel compressok = nvlist_exists(innvl, "compressok"); 6121eb633035STom Caputi rawok = nvlist_exists(innvl, "rawok"); 61225d7b4d43SMatthew Ahrens 61239c3fd121SMatthew Ahrens (void) nvlist_lookup_uint64(innvl, "resume_object", &resumeobj); 61249c3fd121SMatthew Ahrens (void) nvlist_lookup_uint64(innvl, "resume_offset", &resumeoff); 61259c3fd121SMatthew Ahrens 61264445fffbSMatthew Ahrens file_t *fp = getf(fd); 61273b2aab18SMatthew Ahrens if (fp == NULL) 6128be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 61294445fffbSMatthew Ahrens 61304445fffbSMatthew Ahrens off = fp->f_offset; 61315602294fSDan Kimmel error = dmu_send(snapname, fromname, embedok, largeblockok, compressok, 6132eb633035STom Caputi rawok, fd, resumeobj, resumeoff, fp->f_vnode, &off); 61334445fffbSMatthew Ahrens 61344445fffbSMatthew Ahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 61354445fffbSMatthew Ahrens fp->f_offset = off; 61364445fffbSMatthew Ahrens releasef(fd); 61374445fffbSMatthew Ahrens return (error); 61384445fffbSMatthew Ahrens } 61394445fffbSMatthew Ahrens 61404445fffbSMatthew Ahrens /* 61414445fffbSMatthew Ahrens * Determine approximately how large a zfs send stream will be -- the number 61424445fffbSMatthew Ahrens * of bytes that will be written to the fd supplied to zfs_ioc_send_new(). 61434445fffbSMatthew Ahrens * 61444445fffbSMatthew Ahrens * innvl: { 6145643da460SMax Grossman * (optional) "from" -> full snap or bookmark name to send an incremental 6146643da460SMax Grossman * from 61475602294fSDan Kimmel * (optional) "largeblockok" -> (value ignored) 61485602294fSDan Kimmel * indicates that blocks > 128KB are permitted 61495602294fSDan Kimmel * (optional) "embedok" -> (value ignored) 61505602294fSDan Kimmel * presence indicates DRR_WRITE_EMBEDDED records are permitted 61515602294fSDan Kimmel * (optional) "compressok" -> (value ignored) 61525602294fSDan Kimmel * presence indicates compressed DRR_WRITE records are permitted 61534445fffbSMatthew Ahrens * } 61544445fffbSMatthew Ahrens * 61554445fffbSMatthew Ahrens * outnvl: { 61564445fffbSMatthew Ahrens * "space" -> bytes of space (uint64) 61574445fffbSMatthew Ahrens * } 61584445fffbSMatthew Ahrens */ 61594445fffbSMatthew Ahrens static int 61604445fffbSMatthew Ahrens zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) 61614445fffbSMatthew Ahrens { 61623b2aab18SMatthew Ahrens dsl_pool_t *dp; 61633b2aab18SMatthew Ahrens dsl_dataset_t *tosnap; 61644445fffbSMatthew Ahrens int error; 61654445fffbSMatthew Ahrens char *fromname; 61665602294fSDan Kimmel boolean_t compressok; 6167eb633035STom Caputi boolean_t rawok; 61684445fffbSMatthew Ahrens uint64_t space; 61694445fffbSMatthew Ahrens 61703b2aab18SMatthew Ahrens error = dsl_pool_hold(snapname, FTAG, &dp); 61713b2aab18SMatthew Ahrens if (error != 0) 61723b2aab18SMatthew Ahrens return (error); 61733b2aab18SMatthew Ahrens 61743b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, snapname, FTAG, &tosnap); 61753b2aab18SMatthew Ahrens if (error != 0) { 61763b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 61774445fffbSMatthew Ahrens return (error); 61783b2aab18SMatthew Ahrens } 61794445fffbSMatthew Ahrens 61805602294fSDan Kimmel compressok = nvlist_exists(innvl, "compressok"); 6181eb633035STom Caputi rawok = nvlist_exists(innvl, "rawok"); 61825602294fSDan Kimmel 6183643da460SMax Grossman error = nvlist_lookup_string(innvl, "from", &fromname); 61844445fffbSMatthew Ahrens if (error == 0) { 6185643da460SMax Grossman if (strchr(fromname, '@') != NULL) { 6186643da460SMax Grossman /* 6187643da460SMax Grossman * If from is a snapshot, hold it and use the more 6188643da460SMax Grossman * efficient dmu_send_estimate to estimate send space 6189643da460SMax Grossman * size using deadlists. 6190643da460SMax Grossman */ 6191643da460SMax Grossman dsl_dataset_t *fromsnap; 6192643da460SMax Grossman error = dsl_dataset_hold(dp, fromname, FTAG, &fromsnap); 6193643da460SMax Grossman if (error != 0) 6194643da460SMax Grossman goto out; 6195eb633035STom Caputi error = dmu_send_estimate(tosnap, fromsnap, 6196eb633035STom Caputi compressok || rawok, &space); 6197643da460SMax Grossman dsl_dataset_rele(fromsnap, FTAG); 6198643da460SMax Grossman } else if (strchr(fromname, '#') != NULL) { 6199643da460SMax Grossman /* 6200643da460SMax Grossman * If from is a bookmark, fetch the creation TXG of the 6201643da460SMax Grossman * snapshot it was created from and use that to find 6202643da460SMax Grossman * blocks that were born after it. 6203643da460SMax Grossman */ 6204643da460SMax Grossman zfs_bookmark_phys_t frombm; 6205643da460SMax Grossman 6206643da460SMax Grossman error = dsl_bookmark_lookup(dp, fromname, tosnap, 6207643da460SMax Grossman &frombm); 6208643da460SMax Grossman if (error != 0) 6209643da460SMax Grossman goto out; 6210643da460SMax Grossman error = dmu_send_estimate_from_txg(tosnap, 6211eb633035STom Caputi frombm.zbm_creation_txg, compressok || rawok, 6212eb633035STom Caputi &space); 6213643da460SMax Grossman } else { 6214643da460SMax Grossman /* 6215643da460SMax Grossman * from is not properly formatted as a snapshot or 6216643da460SMax Grossman * bookmark 6217643da460SMax Grossman */ 6218643da460SMax Grossman error = SET_ERROR(EINVAL); 6219643da460SMax Grossman goto out; 62204445fffbSMatthew Ahrens } 6221643da460SMax Grossman } else { 6222b852c2f5SToomas Soome /* 6223b852c2f5SToomas Soome * If estimating the size of a full send, use dmu_send_estimate. 6224b852c2f5SToomas Soome */ 6225eb633035STom Caputi error = dmu_send_estimate(tosnap, NULL, compressok || rawok, 6226eb633035STom Caputi &space); 62274445fffbSMatthew Ahrens } 62284445fffbSMatthew Ahrens 62294445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "space", space); 62304445fffbSMatthew Ahrens 6231643da460SMax Grossman out: 62323b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 62333b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 62344445fffbSMatthew Ahrens return (error); 62354445fffbSMatthew Ahrens } 62364445fffbSMatthew Ahrens 62379c2acf00SAlek Pinchuk /* 62389c2acf00SAlek Pinchuk * Sync the currently open TXG to disk for the specified pool. 62399c2acf00SAlek Pinchuk * This is somewhat similar to 'zfs_sync()'. 62409c2acf00SAlek Pinchuk * For cases that do not result in error this ioctl will wait for 62419c2acf00SAlek Pinchuk * the currently open TXG to commit before returning back to the caller. 62429c2acf00SAlek Pinchuk * 62439c2acf00SAlek Pinchuk * innvl: { 62449c2acf00SAlek Pinchuk * "force" -> when true, force uberblock update even if there is no dirty data. 62459c2acf00SAlek Pinchuk * In addition this will cause the vdev configuration to be written 62469c2acf00SAlek Pinchuk * out including updating the zpool cache file. (boolean_t) 62479c2acf00SAlek Pinchuk * } 62489c2acf00SAlek Pinchuk * 62499c2acf00SAlek Pinchuk * onvl is unused 62509c2acf00SAlek Pinchuk */ 62519c2acf00SAlek Pinchuk /* ARGSUSED */ 62529c2acf00SAlek Pinchuk static int 62539c2acf00SAlek Pinchuk zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl) 62549c2acf00SAlek Pinchuk { 62559c2acf00SAlek Pinchuk int err; 62569c2acf00SAlek Pinchuk boolean_t force; 62579c2acf00SAlek Pinchuk spa_t *spa; 62589c2acf00SAlek Pinchuk 62599c2acf00SAlek Pinchuk if ((err = spa_open(pool, &spa, FTAG)) != 0) 62609c2acf00SAlek Pinchuk return (err); 62619c2acf00SAlek Pinchuk 62629c2acf00SAlek Pinchuk force = fnvlist_lookup_boolean_value(innvl, "force"); 62639c2acf00SAlek Pinchuk if (force) { 62649c2acf00SAlek Pinchuk spa_config_enter(spa, SCL_CONFIG, FTAG, RW_WRITER); 62659c2acf00SAlek Pinchuk vdev_config_dirty(spa->spa_root_vdev); 62669c2acf00SAlek Pinchuk spa_config_exit(spa, SCL_CONFIG, FTAG); 62679c2acf00SAlek Pinchuk } 62689c2acf00SAlek Pinchuk txg_wait_synced(spa_get_dsl(spa), 0); 62699c2acf00SAlek Pinchuk 62709c2acf00SAlek Pinchuk spa_close(spa, FTAG); 62719c2acf00SAlek Pinchuk 62729c2acf00SAlek Pinchuk return (err); 62739c2acf00SAlek Pinchuk } 62749c2acf00SAlek Pinchuk 6275eb633035STom Caputi /* 6276eb633035STom Caputi * Load a user's wrapping key into the kernel. 6277eb633035STom Caputi * innvl: { 6278eb633035STom Caputi * "hidden_args" -> { "wkeydata" -> value } 6279eb633035STom Caputi * raw uint8_t array of encryption wrapping key data (32 bytes) 6280eb633035STom Caputi * (optional) "noop" -> (value ignored) 6281eb633035STom Caputi * presence indicated key should only be verified, not loaded 6282eb633035STom Caputi * } 6283eb633035STom Caputi */ 6284eb633035STom Caputi /* ARGSUSED */ 6285eb633035STom Caputi static int 6286eb633035STom Caputi zfs_ioc_load_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl) 6287eb633035STom Caputi { 6288eb633035STom Caputi int ret = 0; 6289eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 6290eb633035STom Caputi nvlist_t *hidden_args; 6291eb633035STom Caputi boolean_t noop = nvlist_exists(innvl, "noop"); 6292eb633035STom Caputi 6293eb633035STom Caputi if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) { 6294eb633035STom Caputi ret = SET_ERROR(EINVAL); 6295eb633035STom Caputi goto error; 6296eb633035STom Caputi } 6297eb633035STom Caputi 6298eb633035STom Caputi ret = nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args); 6299eb633035STom Caputi if (ret != 0) { 6300eb633035STom Caputi ret = SET_ERROR(EINVAL); 6301eb633035STom Caputi goto error; 6302eb633035STom Caputi } 6303eb633035STom Caputi 6304eb633035STom Caputi ret = dsl_crypto_params_create_nvlist(DCP_CMD_NONE, NULL, 6305eb633035STom Caputi hidden_args, &dcp); 6306eb633035STom Caputi if (ret != 0) 6307eb633035STom Caputi goto error; 6308eb633035STom Caputi 6309eb633035STom Caputi ret = spa_keystore_load_wkey(dsname, dcp, noop); 6310eb633035STom Caputi if (ret != 0) 6311eb633035STom Caputi goto error; 6312eb633035STom Caputi 6313eb633035STom Caputi dsl_crypto_params_free(dcp, noop); 6314eb633035STom Caputi 6315eb633035STom Caputi return (0); 6316eb633035STom Caputi 6317eb633035STom Caputi error: 6318eb633035STom Caputi dsl_crypto_params_free(dcp, B_TRUE); 6319eb633035STom Caputi return (ret); 6320eb633035STom Caputi } 6321eb633035STom Caputi 6322eb633035STom Caputi /* 6323eb633035STom Caputi * Unload a user's wrapping key from the kernel. 6324eb633035STom Caputi * Both innvl and outnvl are unused. 6325eb633035STom Caputi */ 6326eb633035STom Caputi /* ARGSUSED */ 6327eb633035STom Caputi static int 6328eb633035STom Caputi zfs_ioc_unload_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl) 6329eb633035STom Caputi { 6330eb633035STom Caputi int ret = 0; 6331eb633035STom Caputi 6332eb633035STom Caputi if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) { 6333eb633035STom Caputi ret = (SET_ERROR(EINVAL)); 6334eb633035STom Caputi goto out; 6335eb633035STom Caputi } 6336eb633035STom Caputi 6337eb633035STom Caputi ret = spa_keystore_unload_wkey(dsname); 6338eb633035STom Caputi if (ret != 0) 6339eb633035STom Caputi goto out; 6340eb633035STom Caputi 6341eb633035STom Caputi out: 6342eb633035STom Caputi return (ret); 6343eb633035STom Caputi } 6344eb633035STom Caputi 6345eb633035STom Caputi /* 6346eb633035STom Caputi * Changes a user's wrapping key used to decrypt a dataset. The keyformat, 6347eb633035STom Caputi * keylocation, pbkdf2salt, and pbkdf2iters properties can also be specified 6348eb633035STom Caputi * here to change how the key is derived in userspace. 6349eb633035STom Caputi * 6350eb633035STom Caputi * innvl: { 6351eb633035STom Caputi * "hidden_args" (optional) -> { "wkeydata" -> value } 6352eb633035STom Caputi * raw uint8_t array of new encryption wrapping key data (32 bytes) 6353eb633035STom Caputi * "props" (optional) -> { prop -> value } 6354eb633035STom Caputi * } 6355eb633035STom Caputi * 6356eb633035STom Caputi * outnvl is unused 6357eb633035STom Caputi */ 6358eb633035STom Caputi /* ARGSUSED */ 6359eb633035STom Caputi static int 6360eb633035STom Caputi zfs_ioc_change_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl) 6361eb633035STom Caputi { 6362eb633035STom Caputi int ret; 6363eb633035STom Caputi uint64_t cmd = DCP_CMD_NONE; 6364eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 6365eb633035STom Caputi nvlist_t *args = NULL, *hidden_args = NULL; 6366eb633035STom Caputi 6367eb633035STom Caputi if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) { 6368eb633035STom Caputi ret = (SET_ERROR(EINVAL)); 6369eb633035STom Caputi goto error; 6370eb633035STom Caputi } 6371eb633035STom Caputi 6372eb633035STom Caputi (void) nvlist_lookup_uint64(innvl, "crypt_cmd", &cmd); 6373eb633035STom Caputi (void) nvlist_lookup_nvlist(innvl, "props", &args); 6374eb633035STom Caputi (void) nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args); 6375eb633035STom Caputi 6376eb633035STom Caputi ret = dsl_crypto_params_create_nvlist(cmd, args, hidden_args, &dcp); 6377eb633035STom Caputi if (ret != 0) 6378eb633035STom Caputi goto error; 6379eb633035STom Caputi 6380eb633035STom Caputi ret = spa_keystore_change_key(dsname, dcp); 6381eb633035STom Caputi if (ret != 0) 6382eb633035STom Caputi goto error; 6383eb633035STom Caputi 6384eb633035STom Caputi dsl_crypto_params_free(dcp, B_FALSE); 6385eb633035STom Caputi 6386eb633035STom Caputi return (0); 6387eb633035STom Caputi 6388eb633035STom Caputi error: 6389eb633035STom Caputi dsl_crypto_params_free(dcp, B_TRUE); 6390eb633035STom Caputi return (ret); 6391eb633035STom Caputi } 6392eb633035STom Caputi 63934445fffbSMatthew Ahrens static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST]; 63944445fffbSMatthew Ahrens 63954445fffbSMatthew Ahrens static void 63964445fffbSMatthew Ahrens zfs_ioctl_register_legacy(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 63974445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck, 63984445fffbSMatthew Ahrens boolean_t log_history, zfs_ioc_poolcheck_t pool_check) 63994445fffbSMatthew Ahrens { 64004445fffbSMatthew Ahrens zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST]; 64014445fffbSMatthew Ahrens 64024445fffbSMatthew Ahrens ASSERT3U(ioc, >=, ZFS_IOC_FIRST); 64034445fffbSMatthew Ahrens ASSERT3U(ioc, <, ZFS_IOC_LAST); 64044445fffbSMatthew Ahrens ASSERT3P(vec->zvec_legacy_func, ==, NULL); 64054445fffbSMatthew Ahrens ASSERT3P(vec->zvec_func, ==, NULL); 64064445fffbSMatthew Ahrens 64074445fffbSMatthew Ahrens vec->zvec_legacy_func = func; 64084445fffbSMatthew Ahrens vec->zvec_secpolicy = secpolicy; 64094445fffbSMatthew Ahrens vec->zvec_namecheck = namecheck; 64104445fffbSMatthew Ahrens vec->zvec_allow_log = log_history; 64114445fffbSMatthew Ahrens vec->zvec_pool_check = pool_check; 64124445fffbSMatthew Ahrens } 64134445fffbSMatthew Ahrens 64144445fffbSMatthew Ahrens /* 64154445fffbSMatthew Ahrens * See the block comment at the beginning of this file for details on 64164445fffbSMatthew Ahrens * each argument to this function. 64174445fffbSMatthew Ahrens */ 64184445fffbSMatthew Ahrens static void 64194445fffbSMatthew Ahrens zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func, 64204445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck, 64214445fffbSMatthew Ahrens zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist, 64224445fffbSMatthew Ahrens boolean_t allow_log) 64234445fffbSMatthew Ahrens { 64244445fffbSMatthew Ahrens zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST]; 64254445fffbSMatthew Ahrens 64264445fffbSMatthew Ahrens ASSERT3U(ioc, >=, ZFS_IOC_FIRST); 64274445fffbSMatthew Ahrens ASSERT3U(ioc, <, ZFS_IOC_LAST); 64284445fffbSMatthew Ahrens ASSERT3P(vec->zvec_legacy_func, ==, NULL); 64294445fffbSMatthew Ahrens ASSERT3P(vec->zvec_func, ==, NULL); 64304445fffbSMatthew Ahrens 64314445fffbSMatthew Ahrens /* if we are logging, the name must be valid */ 64324445fffbSMatthew Ahrens ASSERT(!allow_log || namecheck != NO_NAME); 64334445fffbSMatthew Ahrens 64344445fffbSMatthew Ahrens vec->zvec_name = name; 64354445fffbSMatthew Ahrens vec->zvec_func = func; 64364445fffbSMatthew Ahrens vec->zvec_secpolicy = secpolicy; 64374445fffbSMatthew Ahrens vec->zvec_namecheck = namecheck; 64384445fffbSMatthew Ahrens vec->zvec_pool_check = pool_check; 64394445fffbSMatthew Ahrens vec->zvec_smush_outnvlist = smush_outnvlist; 64404445fffbSMatthew Ahrens vec->zvec_allow_log = allow_log; 64414445fffbSMatthew Ahrens } 64424445fffbSMatthew Ahrens 64434445fffbSMatthew Ahrens static void 64444445fffbSMatthew Ahrens zfs_ioctl_register_pool(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 64454445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, boolean_t log_history, 64464445fffbSMatthew Ahrens zfs_ioc_poolcheck_t pool_check) 64474445fffbSMatthew Ahrens { 64484445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 64494445fffbSMatthew Ahrens POOL_NAME, log_history, pool_check); 64504445fffbSMatthew Ahrens } 64514445fffbSMatthew Ahrens 64524445fffbSMatthew Ahrens static void 64534445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 64544445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, zfs_ioc_poolcheck_t pool_check) 64554445fffbSMatthew Ahrens { 64564445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 64574445fffbSMatthew Ahrens DATASET_NAME, B_FALSE, pool_check); 64584445fffbSMatthew Ahrens } 64594445fffbSMatthew Ahrens 64604445fffbSMatthew Ahrens static void 64614445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func) 64624445fffbSMatthew Ahrens { 64634445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, zfs_secpolicy_config, 64644445fffbSMatthew Ahrens POOL_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 64654445fffbSMatthew Ahrens } 64664445fffbSMatthew Ahrens 64674445fffbSMatthew Ahrens static void 64684445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 64694445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy) 64704445fffbSMatthew Ahrens { 64714445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 64724445fffbSMatthew Ahrens NO_NAME, B_FALSE, POOL_CHECK_NONE); 64734445fffbSMatthew Ahrens } 64744445fffbSMatthew Ahrens 64754445fffbSMatthew Ahrens static void 64764445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(zfs_ioc_t ioc, 64774445fffbSMatthew Ahrens zfs_ioc_legacy_func_t *func, zfs_secpolicy_func_t *secpolicy) 64784445fffbSMatthew Ahrens { 64794445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 64804445fffbSMatthew Ahrens DATASET_NAME, B_FALSE, POOL_CHECK_SUSPENDED); 64814445fffbSMatthew Ahrens } 64824445fffbSMatthew Ahrens 64834445fffbSMatthew Ahrens static void 64844445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func) 64854445fffbSMatthew Ahrens { 64864445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ioc, func, 64874445fffbSMatthew Ahrens zfs_secpolicy_read); 64884445fffbSMatthew Ahrens } 64894445fffbSMatthew Ahrens 64904445fffbSMatthew Ahrens static void 64914445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 64929a686fbcSPaul Dagnelie zfs_secpolicy_func_t *secpolicy) 64934445fffbSMatthew Ahrens { 64944445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 64954445fffbSMatthew Ahrens DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 64964445fffbSMatthew Ahrens } 64974445fffbSMatthew Ahrens 64984445fffbSMatthew Ahrens static void 64994445fffbSMatthew Ahrens zfs_ioctl_init(void) 65004445fffbSMatthew Ahrens { 65014445fffbSMatthew Ahrens zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT, 65024445fffbSMatthew Ahrens zfs_ioc_snapshot, zfs_secpolicy_snapshot, POOL_NAME, 65034445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 65044445fffbSMatthew Ahrens 65054445fffbSMatthew Ahrens zfs_ioctl_register("log_history", ZFS_IOC_LOG_HISTORY, 65064445fffbSMatthew Ahrens zfs_ioc_log_history, zfs_secpolicy_log_history, NO_NAME, 65074445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE); 65084445fffbSMatthew Ahrens 65094445fffbSMatthew Ahrens zfs_ioctl_register("space_snaps", ZFS_IOC_SPACE_SNAPS, 65104445fffbSMatthew Ahrens zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME, 65114445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 65124445fffbSMatthew Ahrens 65134445fffbSMatthew Ahrens zfs_ioctl_register("send", ZFS_IOC_SEND_NEW, 65144445fffbSMatthew Ahrens zfs_ioc_send_new, zfs_secpolicy_send_new, DATASET_NAME, 65154445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 65164445fffbSMatthew Ahrens 65174445fffbSMatthew Ahrens zfs_ioctl_register("send_space", ZFS_IOC_SEND_SPACE, 65184445fffbSMatthew Ahrens zfs_ioc_send_space, zfs_secpolicy_read, DATASET_NAME, 65194445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 65204445fffbSMatthew Ahrens 65214445fffbSMatthew Ahrens zfs_ioctl_register("create", ZFS_IOC_CREATE, 65224445fffbSMatthew Ahrens zfs_ioc_create, zfs_secpolicy_create_clone, DATASET_NAME, 65234445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 65244445fffbSMatthew Ahrens 65254445fffbSMatthew Ahrens zfs_ioctl_register("clone", ZFS_IOC_CLONE, 65264445fffbSMatthew Ahrens zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME, 65274445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 65284445fffbSMatthew Ahrens 65295cabbc6bSPrashanth Sreenivasa zfs_ioctl_register("remap", ZFS_IOC_REMAP, 65305cabbc6bSPrashanth Sreenivasa zfs_ioc_remap, zfs_secpolicy_remap, DATASET_NAME, 65315cabbc6bSPrashanth Sreenivasa POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE); 65325cabbc6bSPrashanth Sreenivasa 65334445fffbSMatthew Ahrens zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS, 65344445fffbSMatthew Ahrens zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME, 65354445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 65364445fffbSMatthew Ahrens 65373b2aab18SMatthew Ahrens zfs_ioctl_register("hold", ZFS_IOC_HOLD, 65383b2aab18SMatthew Ahrens zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME, 65393b2aab18SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 65403b2aab18SMatthew Ahrens zfs_ioctl_register("release", ZFS_IOC_RELEASE, 65413b2aab18SMatthew Ahrens zfs_ioc_release, zfs_secpolicy_release, POOL_NAME, 65423b2aab18SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 65433b2aab18SMatthew Ahrens 65443b2aab18SMatthew Ahrens zfs_ioctl_register("get_holds", ZFS_IOC_GET_HOLDS, 65453b2aab18SMatthew Ahrens zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, 65463b2aab18SMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 65473b2aab18SMatthew Ahrens 6548a7027df1SMatthew Ahrens zfs_ioctl_register("rollback", ZFS_IOC_ROLLBACK, 6549a7027df1SMatthew Ahrens zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, 6550a7027df1SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE); 6551a7027df1SMatthew Ahrens 655278f17100SMatthew Ahrens zfs_ioctl_register("bookmark", ZFS_IOC_BOOKMARK, 655378f17100SMatthew Ahrens zfs_ioc_bookmark, zfs_secpolicy_bookmark, POOL_NAME, 655478f17100SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 655578f17100SMatthew Ahrens 655678f17100SMatthew Ahrens zfs_ioctl_register("get_bookmarks", ZFS_IOC_GET_BOOKMARKS, 655778f17100SMatthew Ahrens zfs_ioc_get_bookmarks, zfs_secpolicy_read, DATASET_NAME, 655878f17100SMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 655978f17100SMatthew Ahrens 656078f17100SMatthew Ahrens zfs_ioctl_register("destroy_bookmarks", ZFS_IOC_DESTROY_BOOKMARKS, 656178f17100SMatthew Ahrens zfs_ioc_destroy_bookmarks, zfs_secpolicy_destroy_bookmarks, 656278f17100SMatthew Ahrens POOL_NAME, 656378f17100SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 656478f17100SMatthew Ahrens 6565dfc11533SChris Williamson zfs_ioctl_register("channel_program", ZFS_IOC_CHANNEL_PROGRAM, 6566dfc11533SChris Williamson zfs_ioc_channel_program, zfs_secpolicy_config, 6567dfc11533SChris Williamson POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, 6568dfc11533SChris Williamson B_TRUE); 6569dfc11533SChris Williamson 657086714001SSerapheim Dimitropoulos zfs_ioctl_register("zpool_checkpoint", ZFS_IOC_POOL_CHECKPOINT, 657186714001SSerapheim Dimitropoulos zfs_ioc_pool_checkpoint, zfs_secpolicy_config, POOL_NAME, 657286714001SSerapheim Dimitropoulos POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 657386714001SSerapheim Dimitropoulos 657486714001SSerapheim Dimitropoulos zfs_ioctl_register("zpool_discard_checkpoint", 657586714001SSerapheim Dimitropoulos ZFS_IOC_POOL_DISCARD_CHECKPOINT, zfs_ioc_pool_discard_checkpoint, 657686714001SSerapheim Dimitropoulos zfs_secpolicy_config, POOL_NAME, 657786714001SSerapheim Dimitropoulos POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 657886714001SSerapheim Dimitropoulos 6579094e47e9SGeorge Wilson zfs_ioctl_register("initialize", ZFS_IOC_POOL_INITIALIZE, 6580094e47e9SGeorge Wilson zfs_ioc_pool_initialize, zfs_secpolicy_config, POOL_NAME, 6581094e47e9SGeorge Wilson POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 6582094e47e9SGeorge Wilson 6583*084fd14fSBrian Behlendorf zfs_ioctl_register("trim", ZFS_IOC_POOL_TRIM, 6584*084fd14fSBrian Behlendorf zfs_ioc_pool_trim, zfs_secpolicy_config, POOL_NAME, 6585*084fd14fSBrian Behlendorf POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 6586*084fd14fSBrian Behlendorf 65879c2acf00SAlek Pinchuk zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC, 65889c2acf00SAlek Pinchuk zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME, 65899c2acf00SAlek Pinchuk POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE); 65909c2acf00SAlek Pinchuk 6591eb633035STom Caputi zfs_ioctl_register("load-key", ZFS_IOC_LOAD_KEY, 6592eb633035STom Caputi zfs_ioc_load_key, zfs_secpolicy_load_key, 6593eb633035STom Caputi DATASET_NAME, POOL_CHECK_SUSPENDED, B_TRUE, B_TRUE); 6594eb633035STom Caputi zfs_ioctl_register("unload-key", ZFS_IOC_UNLOAD_KEY, 6595eb633035STom Caputi zfs_ioc_unload_key, zfs_secpolicy_load_key, 6596eb633035STom Caputi DATASET_NAME, POOL_CHECK_SUSPENDED, B_TRUE, B_TRUE); 6597eb633035STom Caputi zfs_ioctl_register("change-key", ZFS_IOC_CHANGE_KEY, 6598eb633035STom Caputi zfs_ioc_change_key, zfs_secpolicy_change_key, 6599eb633035STom Caputi DATASET_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, 6600eb633035STom Caputi B_TRUE, B_TRUE); 6601eb633035STom Caputi 66024445fffbSMatthew Ahrens /* IOCTLS that use the legacy function signature */ 66034445fffbSMatthew Ahrens 66044445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, 66054445fffbSMatthew Ahrens zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_READONLY); 66064445fffbSMatthew Ahrens 66074445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_CREATE, zfs_ioc_pool_create, 66084445fffbSMatthew Ahrens zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); 66094445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SCAN, 66104445fffbSMatthew Ahrens zfs_ioc_pool_scan); 66114445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_UPGRADE, 66124445fffbSMatthew Ahrens zfs_ioc_pool_upgrade); 66134445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ADD, 66144445fffbSMatthew Ahrens zfs_ioc_vdev_add); 66154445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_REMOVE, 66164445fffbSMatthew Ahrens zfs_ioc_vdev_remove); 66174445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SET_STATE, 66184445fffbSMatthew Ahrens zfs_ioc_vdev_set_state); 66194445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ATTACH, 66204445fffbSMatthew Ahrens zfs_ioc_vdev_attach); 66214445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_DETACH, 66224445fffbSMatthew Ahrens zfs_ioc_vdev_detach); 66234445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETPATH, 66244445fffbSMatthew Ahrens zfs_ioc_vdev_setpath); 66254445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETFRU, 66264445fffbSMatthew Ahrens zfs_ioc_vdev_setfru); 66274445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SET_PROPS, 66284445fffbSMatthew Ahrens zfs_ioc_pool_set_props); 66294445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SPLIT, 66304445fffbSMatthew Ahrens zfs_ioc_vdev_split); 66314445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_REGUID, 66324445fffbSMatthew Ahrens zfs_ioc_pool_reguid); 66334445fffbSMatthew Ahrens 66344445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_POOL_CONFIGS, 66354445fffbSMatthew Ahrens zfs_ioc_pool_configs, zfs_secpolicy_none); 66364445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_POOL_TRYIMPORT, 66374445fffbSMatthew Ahrens zfs_ioc_pool_tryimport, zfs_secpolicy_config); 66384445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_INJECT_FAULT, 66394445fffbSMatthew Ahrens zfs_ioc_inject_fault, zfs_secpolicy_inject); 66404445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_CLEAR_FAULT, 66414445fffbSMatthew Ahrens zfs_ioc_clear_fault, zfs_secpolicy_inject); 66424445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_INJECT_LIST_NEXT, 66434445fffbSMatthew Ahrens zfs_ioc_inject_list_next, zfs_secpolicy_inject); 66444445fffbSMatthew Ahrens 66454445fffbSMatthew Ahrens /* 66464445fffbSMatthew Ahrens * pool destroy, and export don't log the history as part of 66474445fffbSMatthew Ahrens * zfsdev_ioctl, but rather zfs_ioc_pool_export 66484445fffbSMatthew Ahrens * does the logging of those commands. 66494445fffbSMatthew Ahrens */ 66504445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_DESTROY, zfs_ioc_pool_destroy, 66514445fffbSMatthew Ahrens zfs_secpolicy_config, B_FALSE, POOL_CHECK_NONE); 66524445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_EXPORT, zfs_ioc_pool_export, 66534445fffbSMatthew Ahrens zfs_secpolicy_config, B_FALSE, POOL_CHECK_NONE); 66544445fffbSMatthew Ahrens 66554445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_STATS, zfs_ioc_pool_stats, 66564445fffbSMatthew Ahrens zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE); 66574445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_PROPS, zfs_ioc_pool_get_props, 66584445fffbSMatthew Ahrens zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE); 66594445fffbSMatthew Ahrens 66604445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_ERROR_LOG, zfs_ioc_error_log, 66614445fffbSMatthew Ahrens zfs_secpolicy_inject, B_FALSE, POOL_CHECK_SUSPENDED); 66624445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_DSOBJ_TO_DSNAME, 66634445fffbSMatthew Ahrens zfs_ioc_dsobj_to_dsname, 66644445fffbSMatthew Ahrens zfs_secpolicy_diff, B_FALSE, POOL_CHECK_SUSPENDED); 66654445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_HISTORY, 66664445fffbSMatthew Ahrens zfs_ioc_pool_get_history, 66674445fffbSMatthew Ahrens zfs_secpolicy_config, B_FALSE, POOL_CHECK_SUSPENDED); 66684445fffbSMatthew Ahrens 66694445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_IMPORT, zfs_ioc_pool_import, 66704445fffbSMatthew Ahrens zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); 66714445fffbSMatthew Ahrens 66724445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear, 6673f4c1745bSloli zfs_secpolicy_config, B_TRUE, POOL_CHECK_READONLY); 66744445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen, 66754445fffbSMatthew Ahrens zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); 66764445fffbSMatthew Ahrens 66774445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN, 66784445fffbSMatthew Ahrens zfs_ioc_space_written); 66794445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_RECVD_PROPS, 66804445fffbSMatthew Ahrens zfs_ioc_objset_recvd_props); 66814445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_NEXT_OBJ, 66824445fffbSMatthew Ahrens zfs_ioc_next_obj); 66834445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_GET_FSACL, 66844445fffbSMatthew Ahrens zfs_ioc_get_fsacl); 66854445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_STATS, 66864445fffbSMatthew Ahrens zfs_ioc_objset_stats); 66874445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_ZPLPROPS, 66884445fffbSMatthew Ahrens zfs_ioc_objset_zplprops); 66894445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_DATASET_LIST_NEXT, 66904445fffbSMatthew Ahrens zfs_ioc_dataset_list_next); 66914445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_SNAPSHOT_LIST_NEXT, 66924445fffbSMatthew Ahrens zfs_ioc_snapshot_list_next); 66934445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_SEND_PROGRESS, 66944445fffbSMatthew Ahrens zfs_ioc_send_progress); 66954445fffbSMatthew Ahrens 66964445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_DIFF, 66974445fffbSMatthew Ahrens zfs_ioc_diff, zfs_secpolicy_diff); 66984445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_STATS, 66994445fffbSMatthew Ahrens zfs_ioc_obj_to_stats, zfs_secpolicy_diff); 67004445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_PATH, 67014445fffbSMatthew Ahrens zfs_ioc_obj_to_path, zfs_secpolicy_diff); 67024445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_USERSPACE_ONE, 67034445fffbSMatthew Ahrens zfs_ioc_userspace_one, zfs_secpolicy_userspace_one); 67044445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_USERSPACE_MANY, 67054445fffbSMatthew Ahrens zfs_ioc_userspace_many, zfs_secpolicy_userspace_many); 67064445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_SEND, 67074445fffbSMatthew Ahrens zfs_ioc_send, zfs_secpolicy_send); 67084445fffbSMatthew Ahrens 67094445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_PROP, zfs_ioc_set_prop, 67104445fffbSMatthew Ahrens zfs_secpolicy_none); 67114445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy, 67124445fffbSMatthew Ahrens zfs_secpolicy_destroy); 67134445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_RENAME, zfs_ioc_rename, 67144445fffbSMatthew Ahrens zfs_secpolicy_rename); 67154445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_RECV, zfs_ioc_recv, 67164445fffbSMatthew Ahrens zfs_secpolicy_recv); 67174445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_PROMOTE, zfs_ioc_promote, 67184445fffbSMatthew Ahrens zfs_secpolicy_promote); 67194445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_INHERIT_PROP, 67204445fffbSMatthew Ahrens zfs_ioc_inherit_prop, zfs_secpolicy_inherit_prop); 67214445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_FSACL, zfs_ioc_set_fsacl, 67224445fffbSMatthew Ahrens zfs_secpolicy_set_fsacl); 67234445fffbSMatthew Ahrens 67244445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_SHARE, zfs_ioc_share, 67254445fffbSMatthew Ahrens zfs_secpolicy_share, POOL_CHECK_NONE); 67264445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_SMB_ACL, zfs_ioc_smb_acl, 67274445fffbSMatthew Ahrens zfs_secpolicy_smb_acl, POOL_CHECK_NONE); 67284445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_USERSPACE_UPGRADE, 67294445fffbSMatthew Ahrens zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 67304445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 67314445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_TMP_SNAPSHOT, 67324445fffbSMatthew Ahrens zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot, 67334445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 67344445fffbSMatthew Ahrens } 6735fa9e4066Sahrens 673654d692b7SGeorge Wilson int 6737f9af39baSGeorge Wilson pool_status_check(const char *name, zfs_ioc_namecheck_t type, 6738f9af39baSGeorge Wilson zfs_ioc_poolcheck_t check) 673954d692b7SGeorge Wilson { 674054d692b7SGeorge Wilson spa_t *spa; 674154d692b7SGeorge Wilson int error; 674254d692b7SGeorge Wilson 674354d692b7SGeorge Wilson ASSERT(type == POOL_NAME || type == DATASET_NAME); 674454d692b7SGeorge Wilson 6745f9af39baSGeorge Wilson if (check & POOL_CHECK_NONE) 6746f9af39baSGeorge Wilson return (0); 6747f9af39baSGeorge Wilson 674814843421SMatthew Ahrens error = spa_open(name, &spa, FTAG); 674954d692b7SGeorge Wilson if (error == 0) { 6750f9af39baSGeorge Wilson if ((check & POOL_CHECK_SUSPENDED) && spa_suspended(spa)) 6751be6fd75aSMatthew Ahrens error = SET_ERROR(EAGAIN); 6752f9af39baSGeorge Wilson else if ((check & POOL_CHECK_READONLY) && !spa_writeable(spa)) 6753be6fd75aSMatthew Ahrens error = SET_ERROR(EROFS); 675454d692b7SGeorge Wilson spa_close(spa, FTAG); 675554d692b7SGeorge Wilson } 675654d692b7SGeorge Wilson return (error); 675754d692b7SGeorge Wilson } 675854d692b7SGeorge Wilson 6759c99e4bdcSChris Kirby /* 6760c99e4bdcSChris Kirby * Find a free minor number. 6761c99e4bdcSChris Kirby */ 6762c99e4bdcSChris Kirby minor_t 6763c99e4bdcSChris Kirby zfsdev_minor_alloc(void) 6764c99e4bdcSChris Kirby { 6765c99e4bdcSChris Kirby static minor_t last_minor; 6766c99e4bdcSChris Kirby minor_t m; 6767c99e4bdcSChris Kirby 6768c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 6769c99e4bdcSChris Kirby 6770c99e4bdcSChris Kirby for (m = last_minor + 1; m != last_minor; m++) { 6771c99e4bdcSChris Kirby if (m > ZFSDEV_MAX_MINOR) 6772c99e4bdcSChris Kirby m = 1; 6773c99e4bdcSChris Kirby if (ddi_get_soft_state(zfsdev_state, m) == NULL) { 6774c99e4bdcSChris Kirby last_minor = m; 6775c99e4bdcSChris Kirby return (m); 6776c99e4bdcSChris Kirby } 6777c99e4bdcSChris Kirby } 6778c99e4bdcSChris Kirby 6779c99e4bdcSChris Kirby return (0); 6780c99e4bdcSChris Kirby } 6781c99e4bdcSChris Kirby 6782c99e4bdcSChris Kirby static int 6783c99e4bdcSChris Kirby zfs_ctldev_init(dev_t *devp) 6784c99e4bdcSChris Kirby { 6785c99e4bdcSChris Kirby minor_t minor; 6786c99e4bdcSChris Kirby zfs_soft_state_t *zs; 6787c99e4bdcSChris Kirby 6788c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 6789c99e4bdcSChris Kirby ASSERT(getminor(*devp) == 0); 6790c99e4bdcSChris Kirby 6791c99e4bdcSChris Kirby minor = zfsdev_minor_alloc(); 6792c99e4bdcSChris Kirby if (minor == 0) 6793be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 6794c99e4bdcSChris Kirby 6795c99e4bdcSChris Kirby if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) 6796be6fd75aSMatthew Ahrens return (SET_ERROR(EAGAIN)); 6797c99e4bdcSChris Kirby 6798c99e4bdcSChris Kirby *devp = makedevice(getemajor(*devp), minor); 6799c99e4bdcSChris Kirby 6800c99e4bdcSChris Kirby zs = ddi_get_soft_state(zfsdev_state, minor); 6801c99e4bdcSChris Kirby zs->zss_type = ZSST_CTLDEV; 6802c99e4bdcSChris Kirby zfs_onexit_init((zfs_onexit_t **)&zs->zss_data); 6803c99e4bdcSChris Kirby 6804c99e4bdcSChris Kirby return (0); 6805c99e4bdcSChris Kirby } 6806c99e4bdcSChris Kirby 6807c99e4bdcSChris Kirby static void 6808c99e4bdcSChris Kirby zfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor) 6809c99e4bdcSChris Kirby { 6810c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 6811c99e4bdcSChris Kirby 6812c99e4bdcSChris Kirby zfs_onexit_destroy(zo); 6813c99e4bdcSChris Kirby ddi_soft_state_free(zfsdev_state, minor); 6814c99e4bdcSChris Kirby } 6815c99e4bdcSChris Kirby 6816c99e4bdcSChris Kirby void * 6817c99e4bdcSChris Kirby zfsdev_get_soft_state(minor_t minor, enum zfs_soft_state_type which) 6818c99e4bdcSChris Kirby { 6819c99e4bdcSChris Kirby zfs_soft_state_t *zp; 6820c99e4bdcSChris Kirby 6821c99e4bdcSChris Kirby zp = ddi_get_soft_state(zfsdev_state, minor); 6822c99e4bdcSChris Kirby if (zp == NULL || zp->zss_type != which) 6823c99e4bdcSChris Kirby return (NULL); 6824c99e4bdcSChris Kirby 6825c99e4bdcSChris Kirby return (zp->zss_data); 6826c99e4bdcSChris Kirby } 6827c99e4bdcSChris Kirby 6828c99e4bdcSChris Kirby static int 6829c99e4bdcSChris Kirby zfsdev_open(dev_t *devp, int flag, int otyp, cred_t *cr) 6830c99e4bdcSChris Kirby { 6831c99e4bdcSChris Kirby int error = 0; 6832c99e4bdcSChris Kirby 6833c99e4bdcSChris Kirby if (getminor(*devp) != 0) 6834c99e4bdcSChris Kirby return (zvol_open(devp, flag, otyp, cr)); 6835c99e4bdcSChris Kirby 6836c99e4bdcSChris Kirby /* This is the control device. Allocate a new minor if requested. */ 6837c99e4bdcSChris Kirby if (flag & FEXCL) { 6838c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 6839c99e4bdcSChris Kirby error = zfs_ctldev_init(devp); 6840c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 6841c99e4bdcSChris Kirby } 6842c99e4bdcSChris Kirby 6843c99e4bdcSChris Kirby return (error); 6844c99e4bdcSChris Kirby } 6845c99e4bdcSChris Kirby 6846c99e4bdcSChris Kirby static int 6847c99e4bdcSChris Kirby zfsdev_close(dev_t dev, int flag, int otyp, cred_t *cr) 6848c99e4bdcSChris Kirby { 6849c99e4bdcSChris Kirby zfs_onexit_t *zo; 6850c99e4bdcSChris Kirby minor_t minor = getminor(dev); 6851c99e4bdcSChris Kirby 6852c99e4bdcSChris Kirby if (minor == 0) 6853c99e4bdcSChris Kirby return (0); 6854c99e4bdcSChris Kirby 6855c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 6856c99e4bdcSChris Kirby zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); 6857c99e4bdcSChris Kirby if (zo == NULL) { 6858c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 6859c99e4bdcSChris Kirby return (zvol_close(dev, flag, otyp, cr)); 6860c99e4bdcSChris Kirby } 6861c99e4bdcSChris Kirby zfs_ctldev_destroy(zo, minor); 6862c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 6863c99e4bdcSChris Kirby 6864c99e4bdcSChris Kirby return (0); 6865c99e4bdcSChris Kirby } 6866c99e4bdcSChris Kirby 6867fa9e4066Sahrens static int 6868fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 6869fa9e4066Sahrens { 6870fa9e4066Sahrens zfs_cmd_t *zc; 68714445fffbSMatthew Ahrens uint_t vecnum; 68724445fffbSMatthew Ahrens int error, rc, len; 6873c99e4bdcSChris Kirby minor_t minor = getminor(dev); 68744445fffbSMatthew Ahrens const zfs_ioc_vec_t *vec; 68754445fffbSMatthew Ahrens char *saved_poolname = NULL; 68764445fffbSMatthew Ahrens nvlist_t *innvl = NULL; 6877fa9e4066Sahrens 6878c99e4bdcSChris Kirby if (minor != 0 && 6879c99e4bdcSChris Kirby zfsdev_get_soft_state(minor, ZSST_CTLDEV) == NULL) 6880fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 6881fa9e4066Sahrens 68824445fffbSMatthew Ahrens vecnum = cmd - ZFS_IOC_FIRST; 688391ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 6884fa9e4066Sahrens 68854445fffbSMatthew Ahrens if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 6886be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 68874445fffbSMatthew Ahrens vec = &zfs_ioc_vec[vecnum]; 6888fa9e4066Sahrens 6889fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 6890fa9e4066Sahrens 6891478ed9adSEric Taylor error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag); 68924445fffbSMatthew Ahrens if (error != 0) { 6893be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 68944445fffbSMatthew Ahrens goto out; 68954445fffbSMatthew Ahrens } 6896fa9e4066Sahrens 68974445fffbSMatthew Ahrens zc->zc_iflags = flag & FKIOCTL; 68984445fffbSMatthew Ahrens if (zc->zc_nvlist_src_size != 0) { 68994445fffbSMatthew Ahrens error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 69004445fffbSMatthew Ahrens zc->zc_iflags, &innvl); 69014445fffbSMatthew Ahrens if (error != 0) 69024445fffbSMatthew Ahrens goto out; 69034445fffbSMatthew Ahrens } 6904fa9e4066Sahrens 6905fa9e4066Sahrens /* 6906fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 6907fa9e4066Sahrens * the lower layers. 6908fa9e4066Sahrens */ 69094445fffbSMatthew Ahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 69104445fffbSMatthew Ahrens switch (vec->zvec_namecheck) { 69114445fffbSMatthew Ahrens case POOL_NAME: 69124445fffbSMatthew Ahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 6913be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 69144445fffbSMatthew Ahrens else 6915f9af39baSGeorge Wilson error = pool_status_check(zc->zc_name, 69164445fffbSMatthew Ahrens vec->zvec_namecheck, vec->zvec_pool_check); 69174445fffbSMatthew Ahrens break; 6918fa9e4066Sahrens 69194445fffbSMatthew Ahrens case DATASET_NAME: 69204445fffbSMatthew Ahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 6921be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 69224445fffbSMatthew Ahrens else 6923f9af39baSGeorge Wilson error = pool_status_check(zc->zc_name, 69244445fffbSMatthew Ahrens vec->zvec_namecheck, vec->zvec_pool_check); 69254445fffbSMatthew Ahrens break; 69265ad82045Snd 69274445fffbSMatthew Ahrens case NO_NAME: 69284445fffbSMatthew Ahrens break; 6929fa9e4066Sahrens } 6930fa9e4066Sahrens 6931fa9e4066Sahrens 693245b17475SAlex Wilson if (error == 0) 69334445fffbSMatthew Ahrens error = vec->zvec_secpolicy(zc, innvl, cr); 69344445fffbSMatthew Ahrens 69354445fffbSMatthew Ahrens if (error != 0) 69364445fffbSMatthew Ahrens goto out; 69374445fffbSMatthew Ahrens 69384445fffbSMatthew Ahrens /* legacy ioctls can modify zc_name */ 693978f17100SMatthew Ahrens len = strcspn(zc->zc_name, "/@#") + 1; 69404445fffbSMatthew Ahrens saved_poolname = kmem_alloc(len, KM_SLEEP); 69414445fffbSMatthew Ahrens (void) strlcpy(saved_poolname, zc->zc_name, len); 69424445fffbSMatthew Ahrens 69434445fffbSMatthew Ahrens if (vec->zvec_func != NULL) { 69444445fffbSMatthew Ahrens nvlist_t *outnvl; 69454445fffbSMatthew Ahrens int puterror = 0; 69464445fffbSMatthew Ahrens spa_t *spa; 69474445fffbSMatthew Ahrens nvlist_t *lognv = NULL; 69484445fffbSMatthew Ahrens 69494445fffbSMatthew Ahrens ASSERT(vec->zvec_legacy_func == NULL); 69504445fffbSMatthew Ahrens 69514445fffbSMatthew Ahrens /* 69524445fffbSMatthew Ahrens * Add the innvl to the lognv before calling the func, 69534445fffbSMatthew Ahrens * in case the func changes the innvl. 69544445fffbSMatthew Ahrens */ 69554445fffbSMatthew Ahrens if (vec->zvec_allow_log) { 69564445fffbSMatthew Ahrens lognv = fnvlist_alloc(); 69574445fffbSMatthew Ahrens fnvlist_add_string(lognv, ZPOOL_HIST_IOCTL, 69584445fffbSMatthew Ahrens vec->zvec_name); 69594445fffbSMatthew Ahrens if (!nvlist_empty(innvl)) { 69604445fffbSMatthew Ahrens fnvlist_add_nvlist(lognv, ZPOOL_HIST_INPUT_NVL, 69614445fffbSMatthew Ahrens innvl); 69624445fffbSMatthew Ahrens } 69634445fffbSMatthew Ahrens } 69644445fffbSMatthew Ahrens 69654445fffbSMatthew Ahrens outnvl = fnvlist_alloc(); 69664445fffbSMatthew Ahrens error = vec->zvec_func(zc->zc_name, innvl, outnvl); 69674445fffbSMatthew Ahrens 6968dfc11533SChris Williamson /* 6969d0cb1fb9SDon Brady * Some commands can partially execute, modify state, and still 6970dfc11533SChris Williamson * return an error. In these cases, attempt to record what 6971dfc11533SChris Williamson * was modified. 6972dfc11533SChris Williamson */ 6973dfc11533SChris Williamson if ((error == 0 || 6974dfc11533SChris Williamson (cmd == ZFS_IOC_CHANNEL_PROGRAM && error != EINVAL)) && 6975dfc11533SChris Williamson vec->zvec_allow_log && 69764445fffbSMatthew Ahrens spa_open(zc->zc_name, &spa, FTAG) == 0) { 69774445fffbSMatthew Ahrens if (!nvlist_empty(outnvl)) { 69784445fffbSMatthew Ahrens fnvlist_add_nvlist(lognv, ZPOOL_HIST_OUTPUT_NVL, 69794445fffbSMatthew Ahrens outnvl); 69804445fffbSMatthew Ahrens } 6981dfc11533SChris Williamson if (error != 0) { 6982dfc11533SChris Williamson fnvlist_add_int64(lognv, ZPOOL_HIST_ERRNO, 6983dfc11533SChris Williamson error); 6984dfc11533SChris Williamson } 69854445fffbSMatthew Ahrens (void) spa_history_log_nvl(spa, lognv); 69864445fffbSMatthew Ahrens spa_close(spa, FTAG); 69874445fffbSMatthew Ahrens } 69884445fffbSMatthew Ahrens fnvlist_free(lognv); 69894445fffbSMatthew Ahrens 69904445fffbSMatthew Ahrens if (!nvlist_empty(outnvl) || zc->zc_nvlist_dst_size != 0) { 69914445fffbSMatthew Ahrens int smusherror = 0; 69924445fffbSMatthew Ahrens if (vec->zvec_smush_outnvlist) { 69934445fffbSMatthew Ahrens smusherror = nvlist_smush(outnvl, 69944445fffbSMatthew Ahrens zc->zc_nvlist_dst_size); 69954445fffbSMatthew Ahrens } 69964445fffbSMatthew Ahrens if (smusherror == 0) 69974445fffbSMatthew Ahrens puterror = put_nvlist(zc, outnvl); 69984445fffbSMatthew Ahrens } 69994445fffbSMatthew Ahrens 70004445fffbSMatthew Ahrens if (puterror != 0) 70014445fffbSMatthew Ahrens error = puterror; 70024445fffbSMatthew Ahrens 70034445fffbSMatthew Ahrens nvlist_free(outnvl); 70044445fffbSMatthew Ahrens } else { 70054445fffbSMatthew Ahrens error = vec->zvec_legacy_func(zc); 70064445fffbSMatthew Ahrens } 70074445fffbSMatthew Ahrens 70084445fffbSMatthew Ahrens out: 70094445fffbSMatthew Ahrens nvlist_free(innvl); 7010478ed9adSEric Taylor rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag); 70114445fffbSMatthew Ahrens if (error == 0 && rc != 0) 7012be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 70134445fffbSMatthew Ahrens if (error == 0 && vec->zvec_allow_log) { 70144445fffbSMatthew Ahrens char *s = tsd_get(zfs_allow_log_key); 70154445fffbSMatthew Ahrens if (s != NULL) 70164445fffbSMatthew Ahrens strfree(s); 70174445fffbSMatthew Ahrens (void) tsd_set(zfs_allow_log_key, saved_poolname); 70184445fffbSMatthew Ahrens } else { 70194445fffbSMatthew Ahrens if (saved_poolname != NULL) 70204445fffbSMatthew Ahrens strfree(saved_poolname); 7021ecd6cf80Smarks } 7022fa9e4066Sahrens 7023fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 7024fa9e4066Sahrens return (error); 7025fa9e4066Sahrens } 7026fa9e4066Sahrens 7027fa9e4066Sahrens static int 7028fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 7029fa9e4066Sahrens { 7030fa9e4066Sahrens if (cmd != DDI_ATTACH) 7031fa9e4066Sahrens return (DDI_FAILURE); 7032fa9e4066Sahrens 7033fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 7034fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 7035fa9e4066Sahrens return (DDI_FAILURE); 7036fa9e4066Sahrens 7037fa9e4066Sahrens zfs_dip = dip; 7038fa9e4066Sahrens 7039fa9e4066Sahrens ddi_report_dev(dip); 7040fa9e4066Sahrens 7041fa9e4066Sahrens return (DDI_SUCCESS); 7042fa9e4066Sahrens } 7043fa9e4066Sahrens 7044fa9e4066Sahrens static int 7045fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7046fa9e4066Sahrens { 7047fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 7048fa9e4066Sahrens return (DDI_FAILURE); 7049fa9e4066Sahrens 7050fa9e4066Sahrens if (cmd != DDI_DETACH) 7051fa9e4066Sahrens return (DDI_FAILURE); 7052fa9e4066Sahrens 7053fa9e4066Sahrens zfs_dip = NULL; 7054fa9e4066Sahrens 7055fa9e4066Sahrens ddi_prop_remove_all(dip); 7056fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 7057fa9e4066Sahrens 7058fa9e4066Sahrens return (DDI_SUCCESS); 7059fa9e4066Sahrens } 7060fa9e4066Sahrens 7061fa9e4066Sahrens /*ARGSUSED*/ 7062fa9e4066Sahrens static int 7063fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 7064fa9e4066Sahrens { 7065fa9e4066Sahrens switch (infocmd) { 7066fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 7067fa9e4066Sahrens *result = zfs_dip; 7068fa9e4066Sahrens return (DDI_SUCCESS); 7069fa9e4066Sahrens 7070fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 7071a0965f35Sbonwick *result = (void *)0; 7072fa9e4066Sahrens return (DDI_SUCCESS); 7073fa9e4066Sahrens } 7074fa9e4066Sahrens 7075fa9e4066Sahrens return (DDI_FAILURE); 7076fa9e4066Sahrens } 7077fa9e4066Sahrens 7078fa9e4066Sahrens /* 7079fa9e4066Sahrens * OK, so this is a little weird. 7080fa9e4066Sahrens * 7081fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 7082fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 7083fa9e4066Sahrens * 7084fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 7085fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 7086fa9e4066Sahrens */ 7087fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 7088c99e4bdcSChris Kirby zfsdev_open, /* open */ 7089c99e4bdcSChris Kirby zfsdev_close, /* close */ 7090fa9e4066Sahrens zvol_strategy, /* strategy */ 7091fa9e4066Sahrens nodev, /* print */ 7092e7cbe64fSgw zvol_dump, /* dump */ 7093fa9e4066Sahrens zvol_read, /* read */ 7094fa9e4066Sahrens zvol_write, /* write */ 7095fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 7096fa9e4066Sahrens nodev, /* devmap */ 7097fa9e4066Sahrens nodev, /* mmap */ 7098fa9e4066Sahrens nodev, /* segmap */ 7099fa9e4066Sahrens nochpoll, /* poll */ 7100fa9e4066Sahrens ddi_prop_op, /* prop_op */ 7101fa9e4066Sahrens NULL, /* streamtab */ 7102fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 7103fa9e4066Sahrens CB_REV, /* version */ 7104feb08c6bSbillm nodev, /* async read */ 7105feb08c6bSbillm nodev, /* async write */ 7106fa9e4066Sahrens }; 7107fa9e4066Sahrens 7108fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 7109fa9e4066Sahrens DEVO_REV, /* version */ 7110fa9e4066Sahrens 0, /* refcnt */ 7111fa9e4066Sahrens zfs_info, /* info */ 7112fa9e4066Sahrens nulldev, /* identify */ 7113fa9e4066Sahrens nulldev, /* probe */ 7114fa9e4066Sahrens zfs_attach, /* attach */ 7115fa9e4066Sahrens zfs_detach, /* detach */ 7116fa9e4066Sahrens nodev, /* reset */ 7117fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 711819397407SSherry Moore NULL, /* no bus operations */ 711919397407SSherry Moore NULL, /* power */ 712019397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 7121fa9e4066Sahrens }; 7122fa9e4066Sahrens 7123fa9e4066Sahrens static struct modldrv zfs_modldrv = { 712419397407SSherry Moore &mod_driverops, 712519397407SSherry Moore "ZFS storage pool", 712619397407SSherry Moore &zfs_dev_ops 7127fa9e4066Sahrens }; 7128fa9e4066Sahrens 7129fa9e4066Sahrens static struct modlinkage modlinkage = { 7130fa9e4066Sahrens MODREV_1, 7131fa9e4066Sahrens (void *)&zfs_modlfs, 7132fa9e4066Sahrens (void *)&zfs_modldrv, 7133fa9e4066Sahrens NULL 7134fa9e4066Sahrens }; 7135fa9e4066Sahrens 71364445fffbSMatthew Ahrens static void 71374445fffbSMatthew Ahrens zfs_allow_log_destroy(void *arg) 71384445fffbSMatthew Ahrens { 71394445fffbSMatthew Ahrens char *poolname = arg; 71404445fffbSMatthew Ahrens strfree(poolname); 71414445fffbSMatthew Ahrens } 7142ec533521Sfr 7143fa9e4066Sahrens int 7144fa9e4066Sahrens _init(void) 7145fa9e4066Sahrens { 7146fa9e4066Sahrens int error; 7147fa9e4066Sahrens 7148a0965f35Sbonwick spa_init(FREAD | FWRITE); 7149a0965f35Sbonwick zfs_init(); 7150a0965f35Sbonwick zvol_init(); 71514445fffbSMatthew Ahrens zfs_ioctl_init(); 7152a0965f35Sbonwick 7153a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 7154a0965f35Sbonwick zvol_fini(); 7155a0965f35Sbonwick zfs_fini(); 7156a0965f35Sbonwick spa_fini(); 7157fa9e4066Sahrens return (error); 7158a0965f35Sbonwick } 7159fa9e4066Sahrens 7160ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 71614445fffbSMatthew Ahrens tsd_create(&rrw_tsd_key, rrw_tsd_destroy); 71624445fffbSMatthew Ahrens tsd_create(&zfs_allow_log_key, zfs_allow_log_destroy); 7163ec533521Sfr 7164fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 7165fa9e4066Sahrens ASSERT(error == 0); 7166ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 7167fa9e4066Sahrens 7168fa9e4066Sahrens return (0); 7169fa9e4066Sahrens } 7170fa9e4066Sahrens 7171fa9e4066Sahrens int 7172fa9e4066Sahrens _fini(void) 7173fa9e4066Sahrens { 7174fa9e4066Sahrens int error; 7175fa9e4066Sahrens 7176ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 7177be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 7178fa9e4066Sahrens 7179fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 7180fa9e4066Sahrens return (error); 7181fa9e4066Sahrens 7182fa9e4066Sahrens zvol_fini(); 7183fa9e4066Sahrens zfs_fini(); 7184fa9e4066Sahrens spa_fini(); 7185da6c28aaSamw if (zfs_nfsshare_inited) 7186ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 7187da6c28aaSamw if (zfs_smbshare_inited) 7188da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 7189da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 7190ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 7191fa9e4066Sahrens 7192ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 7193fa9e4066Sahrens ldi_ident_release(zfs_li); 7194fa9e4066Sahrens zfs_li = NULL; 7195ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 7196fa9e4066Sahrens 7197fa9e4066Sahrens return (error); 7198fa9e4066Sahrens } 7199fa9e4066Sahrens 7200fa9e4066Sahrens int 7201fa9e4066Sahrens _info(struct modinfo *modinfop) 7202fa9e4066Sahrens { 7203fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 7204fa9e4066Sahrens } 7205