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. 27752fd8daSJosef 'Jeff' Sipek * Copyright 2015 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> 34a4b8c9aaSAndrew Stormont * Copyright 2017 RackTop Systems. 35*eb633035STom Caputi * Copyright (c) 2017, Datto, Inc. All rights reserved. 364445fffbSMatthew Ahrens */ 374445fffbSMatthew Ahrens 384445fffbSMatthew Ahrens /* 394445fffbSMatthew Ahrens * ZFS ioctls. 404445fffbSMatthew Ahrens * 414445fffbSMatthew Ahrens * This file handles the ioctls to /dev/zfs, used for configuring ZFS storage 424445fffbSMatthew Ahrens * pools and filesystems, e.g. with /sbin/zfs and /sbin/zpool. 434445fffbSMatthew Ahrens * 444445fffbSMatthew Ahrens * There are two ways that we handle ioctls: the legacy way where almost 454445fffbSMatthew Ahrens * all of the logic is in the ioctl callback, and the new way where most 464445fffbSMatthew Ahrens * of the marshalling is handled in the common entry point, zfsdev_ioctl(). 474445fffbSMatthew Ahrens * 484445fffbSMatthew Ahrens * Non-legacy ioctls should be registered by calling 494445fffbSMatthew Ahrens * zfs_ioctl_register() from zfs_ioctl_init(). The ioctl is invoked 504445fffbSMatthew Ahrens * from userland by lzc_ioctl(). 514445fffbSMatthew Ahrens * 524445fffbSMatthew Ahrens * The registration arguments are as follows: 534445fffbSMatthew Ahrens * 544445fffbSMatthew Ahrens * const char *name 554445fffbSMatthew Ahrens * The name of the ioctl. This is used for history logging. If the 564445fffbSMatthew Ahrens * ioctl returns successfully (the callback returns 0), and allow_log 574445fffbSMatthew Ahrens * is true, then a history log entry will be recorded with the input & 584445fffbSMatthew Ahrens * output nvlists. The log entry can be printed with "zpool history -i". 594445fffbSMatthew Ahrens * 604445fffbSMatthew Ahrens * zfs_ioc_t ioc 614445fffbSMatthew Ahrens * The ioctl request number, which userland will pass to ioctl(2). 624445fffbSMatthew Ahrens * The ioctl numbers can change from release to release, because 634445fffbSMatthew Ahrens * the caller (libzfs) must be matched to the kernel. 644445fffbSMatthew Ahrens * 654445fffbSMatthew Ahrens * zfs_secpolicy_func_t *secpolicy 664445fffbSMatthew Ahrens * This function will be called before the zfs_ioc_func_t, to 674445fffbSMatthew Ahrens * determine if this operation is permitted. It should return EPERM 684445fffbSMatthew Ahrens * on failure, and 0 on success. Checks include determining if the 694445fffbSMatthew Ahrens * dataset is visible in this zone, and if the user has either all 704445fffbSMatthew Ahrens * zfs privileges in the zone (SYS_MOUNT), or has been granted permission 714445fffbSMatthew Ahrens * to do this operation on this dataset with "zfs allow". 724445fffbSMatthew Ahrens * 734445fffbSMatthew Ahrens * zfs_ioc_namecheck_t namecheck 744445fffbSMatthew Ahrens * This specifies what to expect in the zfs_cmd_t:zc_name -- a pool 754445fffbSMatthew Ahrens * name, a dataset name, or nothing. If the name is not well-formed, 764445fffbSMatthew Ahrens * the ioctl will fail and the callback will not be called. 774445fffbSMatthew Ahrens * Therefore, the callback can assume that the name is well-formed 784445fffbSMatthew Ahrens * (e.g. is null-terminated, doesn't have more than one '@' character, 794445fffbSMatthew Ahrens * doesn't have invalid characters). 804445fffbSMatthew Ahrens * 814445fffbSMatthew Ahrens * zfs_ioc_poolcheck_t pool_check 824445fffbSMatthew Ahrens * This specifies requirements on the pool state. If the pool does 834445fffbSMatthew Ahrens * not meet them (is suspended or is readonly), the ioctl will fail 844445fffbSMatthew Ahrens * and the callback will not be called. If any checks are specified 854445fffbSMatthew Ahrens * (i.e. it is not POOL_CHECK_NONE), namecheck must not be NO_NAME. 864445fffbSMatthew Ahrens * Multiple checks can be or-ed together (e.g. POOL_CHECK_SUSPENDED | 874445fffbSMatthew Ahrens * POOL_CHECK_READONLY). 884445fffbSMatthew Ahrens * 894445fffbSMatthew Ahrens * boolean_t smush_outnvlist 904445fffbSMatthew Ahrens * If smush_outnvlist is true, then the output is presumed to be a 914445fffbSMatthew Ahrens * list of errors, and it will be "smushed" down to fit into the 924445fffbSMatthew Ahrens * caller's buffer, by removing some entries and replacing them with a 934445fffbSMatthew Ahrens * single "N_MORE_ERRORS" entry indicating how many were removed. See 944445fffbSMatthew Ahrens * nvlist_smush() for details. If smush_outnvlist is false, and the 954445fffbSMatthew Ahrens * outnvlist does not fit into the userland-provided buffer, then the 964445fffbSMatthew Ahrens * ioctl will fail with ENOMEM. 974445fffbSMatthew Ahrens * 984445fffbSMatthew Ahrens * zfs_ioc_func_t *func 994445fffbSMatthew Ahrens * The callback function that will perform the operation. 1004445fffbSMatthew Ahrens * 1014445fffbSMatthew Ahrens * The callback should return 0 on success, or an error number on 1024445fffbSMatthew Ahrens * failure. If the function fails, the userland ioctl will return -1, 1034445fffbSMatthew Ahrens * and errno will be set to the callback's return value. The callback 1044445fffbSMatthew Ahrens * will be called with the following arguments: 1054445fffbSMatthew Ahrens * 1064445fffbSMatthew Ahrens * const char *name 1074445fffbSMatthew Ahrens * The name of the pool or dataset to operate on, from 1084445fffbSMatthew Ahrens * zfs_cmd_t:zc_name. The 'namecheck' argument specifies the 1094445fffbSMatthew Ahrens * expected type (pool, dataset, or none). 1104445fffbSMatthew Ahrens * 1114445fffbSMatthew Ahrens * nvlist_t *innvl 1124445fffbSMatthew Ahrens * The input nvlist, deserialized from zfs_cmd_t:zc_nvlist_src. Or 1134445fffbSMatthew Ahrens * NULL if no input nvlist was provided. Changes to this nvlist are 1144445fffbSMatthew Ahrens * ignored. If the input nvlist could not be deserialized, the 1154445fffbSMatthew Ahrens * ioctl will fail and the callback will not be called. 1164445fffbSMatthew Ahrens * 1174445fffbSMatthew Ahrens * nvlist_t *outnvl 1184445fffbSMatthew Ahrens * The output nvlist, initially empty. The callback can fill it in, 1194445fffbSMatthew Ahrens * and it will be returned to userland by serializing it into 1204445fffbSMatthew Ahrens * zfs_cmd_t:zc_nvlist_dst. If it is non-empty, and serialization 1214445fffbSMatthew Ahrens * fails (e.g. because the caller didn't supply a large enough 1224445fffbSMatthew Ahrens * buffer), then the overall ioctl will fail. See the 1234445fffbSMatthew Ahrens * 'smush_nvlist' argument above for additional behaviors. 1244445fffbSMatthew Ahrens * 1254445fffbSMatthew Ahrens * There are two typical uses of the output nvlist: 1264445fffbSMatthew Ahrens * - To return state, e.g. property values. In this case, 1274445fffbSMatthew Ahrens * smush_outnvlist should be false. If the buffer was not large 1284445fffbSMatthew Ahrens * enough, the caller will reallocate a larger buffer and try 1294445fffbSMatthew Ahrens * the ioctl again. 1304445fffbSMatthew Ahrens * 1314445fffbSMatthew Ahrens * - To return multiple errors from an ioctl which makes on-disk 1324445fffbSMatthew Ahrens * changes. In this case, smush_outnvlist should be true. 1334445fffbSMatthew Ahrens * Ioctls which make on-disk modifications should generally not 1344445fffbSMatthew Ahrens * use the outnvl if they succeed, because the caller can not 1354445fffbSMatthew Ahrens * distinguish between the operation failing, and 1364445fffbSMatthew Ahrens * deserialization failing. 137e9103aaeSGarrett D'Amore */ 138fa9e4066Sahrens 139fa9e4066Sahrens #include <sys/types.h> 140fa9e4066Sahrens #include <sys/param.h> 141fa9e4066Sahrens #include <sys/errno.h> 142fa9e4066Sahrens #include <sys/uio.h> 143fa9e4066Sahrens #include <sys/buf.h> 144fa9e4066Sahrens #include <sys/modctl.h> 145fa9e4066Sahrens #include <sys/open.h> 146fa9e4066Sahrens #include <sys/file.h> 147fa9e4066Sahrens #include <sys/kmem.h> 148fa9e4066Sahrens #include <sys/conf.h> 149fa9e4066Sahrens #include <sys/cmn_err.h> 150fa9e4066Sahrens #include <sys/stat.h> 151fa9e4066Sahrens #include <sys/zfs_ioctl.h> 1524201a95eSRic Aleshire #include <sys/zfs_vfsops.h> 153da6c28aaSamw #include <sys/zfs_znode.h> 154fa9e4066Sahrens #include <sys/zap.h> 155fa9e4066Sahrens #include <sys/spa.h> 156b1b8ab34Slling #include <sys/spa_impl.h> 157fa9e4066Sahrens #include <sys/vdev.h> 1584201a95eSRic Aleshire #include <sys/priv_impl.h> 159fa9e4066Sahrens #include <sys/dmu.h> 160fa9e4066Sahrens #include <sys/dsl_dir.h> 161fa9e4066Sahrens #include <sys/dsl_dataset.h> 162fa9e4066Sahrens #include <sys/dsl_prop.h> 163ecd6cf80Smarks #include <sys/dsl_deleg.h> 164ecd6cf80Smarks #include <sys/dmu_objset.h> 1654e3c9f44SBill Pijewski #include <sys/dmu_impl.h> 1663b2aab18SMatthew Ahrens #include <sys/dmu_tx.h> 167fa9e4066Sahrens #include <sys/ddi.h> 168fa9e4066Sahrens #include <sys/sunddi.h> 169fa9e4066Sahrens #include <sys/sunldi.h> 170fa9e4066Sahrens #include <sys/policy.h> 171fa9e4066Sahrens #include <sys/zone.h> 172fa9e4066Sahrens #include <sys/nvpair.h> 173fa9e4066Sahrens #include <sys/pathname.h> 174fa9e4066Sahrens #include <sys/mount.h> 175fa9e4066Sahrens #include <sys/sdt.h> 176fa9e4066Sahrens #include <sys/fs/zfs.h> 177fa9e4066Sahrens #include <sys/zfs_ctldir.h> 178da6c28aaSamw #include <sys/zfs_dir.h> 179c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 180a2eea2e1Sahrens #include <sys/zvol.h> 1813f9d6ad7SLin Ling #include <sys/dsl_scan.h> 182ecd6cf80Smarks #include <sharefs/share.h> 183f18faf3fSek #include <sys/dmu_objset.h> 1840fa1b3ccSPaul Dagnelie #include <sys/dmu_recv.h> 1853b2aab18SMatthew Ahrens #include <sys/dmu_send.h> 1863b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 18778f17100SMatthew Ahrens #include <sys/dsl_bookmark.h> 1883b2aab18SMatthew Ahrens #include <sys/dsl_userhold.h> 189a6f561b4SSašo Kiselkov #include <sys/zfeature.h> 190dfc11533SChris Williamson #include <sys/zcp.h> 19145818ee1SMatthew Ahrens #include <sys/zio_checksum.h> 1925cabbc6bSPrashanth Sreenivasa #include <sys/vdev_removal.h> 193094e47e9SGeorge Wilson #include <sys/vdev_impl.h> 194094e47e9SGeorge Wilson #include <sys/vdev_initialize.h> 195*eb633035STom Caputi #include <sys/dsl_crypt.h> 196fa9e4066Sahrens 197fa9e4066Sahrens #include "zfs_namecheck.h" 198e9dbad6fSeschrock #include "zfs_prop.h" 199ecd6cf80Smarks #include "zfs_deleg.h" 2000a586ceaSMark Shellenbaum #include "zfs_comutil.h" 201fa9e4066Sahrens 202dfc11533SChris Williamson #include "lua.h" 203dfc11533SChris Williamson #include "lauxlib.h" 204dfc11533SChris Williamson 205fa9e4066Sahrens extern struct modlfs zfs_modlfs; 206fa9e4066Sahrens 207fa9e4066Sahrens extern void zfs_init(void); 208fa9e4066Sahrens extern void zfs_fini(void); 209fa9e4066Sahrens 210fa9e4066Sahrens ldi_ident_t zfs_li = NULL; 211fa9e4066Sahrens dev_info_t *zfs_dip; 212fa9e4066Sahrens 2134445fffbSMatthew Ahrens uint_t zfs_fsyncer_key; 2144445fffbSMatthew Ahrens extern uint_t rrw_tsd_key; 2154445fffbSMatthew Ahrens static uint_t zfs_allow_log_key; 2164445fffbSMatthew Ahrens 2174445fffbSMatthew Ahrens typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *); 2184445fffbSMatthew Ahrens typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *); 2194445fffbSMatthew Ahrens typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *); 220fa9e4066Sahrens 22154d692b7SGeorge Wilson typedef enum { 22254d692b7SGeorge Wilson NO_NAME, 22354d692b7SGeorge Wilson POOL_NAME, 22454d692b7SGeorge Wilson DATASET_NAME 22554d692b7SGeorge Wilson } zfs_ioc_namecheck_t; 22654d692b7SGeorge Wilson 227f9af39baSGeorge Wilson typedef enum { 228f9af39baSGeorge Wilson POOL_CHECK_NONE = 1 << 0, 229f9af39baSGeorge Wilson POOL_CHECK_SUSPENDED = 1 << 1, 2304445fffbSMatthew Ahrens POOL_CHECK_READONLY = 1 << 2, 231f9af39baSGeorge Wilson } zfs_ioc_poolcheck_t; 232f9af39baSGeorge Wilson 233fa9e4066Sahrens typedef struct zfs_ioc_vec { 2344445fffbSMatthew Ahrens zfs_ioc_legacy_func_t *zvec_legacy_func; 235fa9e4066Sahrens zfs_ioc_func_t *zvec_func; 236fa9e4066Sahrens zfs_secpolicy_func_t *zvec_secpolicy; 23754d692b7SGeorge Wilson zfs_ioc_namecheck_t zvec_namecheck; 2384445fffbSMatthew Ahrens boolean_t zvec_allow_log; 239f9af39baSGeorge Wilson zfs_ioc_poolcheck_t zvec_pool_check; 2404445fffbSMatthew Ahrens boolean_t zvec_smush_outnvlist; 2414445fffbSMatthew Ahrens const char *zvec_name; 242fa9e4066Sahrens } zfs_ioc_vec_t; 243fa9e4066Sahrens 24414843421SMatthew Ahrens /* This array is indexed by zfs_userquota_prop_t */ 24514843421SMatthew Ahrens static const char *userquota_perms[] = { 24614843421SMatthew Ahrens ZFS_DELEG_PERM_USERUSED, 24714843421SMatthew Ahrens ZFS_DELEG_PERM_USERQUOTA, 24814843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPUSED, 24914843421SMatthew Ahrens ZFS_DELEG_PERM_GROUPQUOTA, 25014843421SMatthew Ahrens }; 25114843421SMatthew Ahrens 25214843421SMatthew Ahrens static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc); 25392241e0bSTom Erickson static int zfs_check_settable(const char *name, nvpair_t *property, 25492241e0bSTom Erickson cred_t *cr); 25592241e0bSTom Erickson static int zfs_check_clearable(char *dataset, nvlist_t *props, 25692241e0bSTom Erickson nvlist_t **errors); 2570a48a24eStimh static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, 2580a48a24eStimh boolean_t *); 2594445fffbSMatthew Ahrens int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *); 2604445fffbSMatthew Ahrens static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp); 2610a48a24eStimh 2622acef22dSMatthew Ahrens static int zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature); 263a6f561b4SSašo Kiselkov 264fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 265fa9e4066Sahrens void 266fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...) 267fa9e4066Sahrens { 268fa9e4066Sahrens const char *newfile; 2693f9d6ad7SLin Ling char buf[512]; 270fa9e4066Sahrens va_list adx; 271fa9e4066Sahrens 272fa9e4066Sahrens /* 273fa9e4066Sahrens * Get rid of annoying "../common/" prefix to filename. 274fa9e4066Sahrens */ 275fa9e4066Sahrens newfile = strrchr(file, '/'); 276fa9e4066Sahrens if (newfile != NULL) { 277fa9e4066Sahrens newfile = newfile + 1; /* Get rid of leading / */ 278fa9e4066Sahrens } else { 279fa9e4066Sahrens newfile = file; 280fa9e4066Sahrens } 281fa9e4066Sahrens 282fa9e4066Sahrens va_start(adx, fmt); 283fa9e4066Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, adx); 284fa9e4066Sahrens va_end(adx); 285fa9e4066Sahrens 286fa9e4066Sahrens /* 287fa9e4066Sahrens * To get this data, use the zfs-dprintf probe as so: 288fa9e4066Sahrens * dtrace -q -n 'zfs-dprintf \ 289fa9e4066Sahrens * /stringof(arg0) == "dbuf.c"/ \ 290fa9e4066Sahrens * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 291fa9e4066Sahrens * arg0 = file name 292fa9e4066Sahrens * arg1 = function name 293fa9e4066Sahrens * arg2 = line number 294fa9e4066Sahrens * arg3 = message 295fa9e4066Sahrens */ 296fa9e4066Sahrens DTRACE_PROBE4(zfs__dprintf, 297fa9e4066Sahrens char *, newfile, char *, func, int, line, char *, buf); 298fa9e4066Sahrens } 299fa9e4066Sahrens 300ecd6cf80Smarks static void 301228975ccSek history_str_free(char *buf) 302228975ccSek { 303228975ccSek kmem_free(buf, HIS_MAX_RECORD_LEN); 304228975ccSek } 305228975ccSek 306228975ccSek static char * 307228975ccSek history_str_get(zfs_cmd_t *zc) 308ecd6cf80Smarks { 30940feaa91Sahrens char *buf; 310ecd6cf80Smarks 311dd328bf6SToomas Soome if (zc->zc_history == 0) 312228975ccSek return (NULL); 313e7437265Sahrens 314ecd6cf80Smarks buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); 315ecd6cf80Smarks if (copyinstr((void *)(uintptr_t)zc->zc_history, 316ecd6cf80Smarks buf, HIS_MAX_RECORD_LEN, NULL) != 0) { 317228975ccSek history_str_free(buf); 318228975ccSek return (NULL); 319ecd6cf80Smarks } 320ecd6cf80Smarks 321ecd6cf80Smarks buf[HIS_MAX_RECORD_LEN -1] = '\0'; 322ecd6cf80Smarks 323228975ccSek return (buf); 324228975ccSek } 325ecd6cf80Smarks 32615e6edf1Sgw /* 32715e6edf1Sgw * Check to see if the named dataset is currently defined as bootable 32815e6edf1Sgw */ 32915e6edf1Sgw static boolean_t 33015e6edf1Sgw zfs_is_bootfs(const char *name) 33115e6edf1Sgw { 332503ad85cSMatthew Ahrens objset_t *os; 33315e6edf1Sgw 334503ad85cSMatthew Ahrens if (dmu_objset_hold(name, FTAG, &os) == 0) { 335503ad85cSMatthew Ahrens boolean_t ret; 336b24ab676SJeff Bonwick ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os))); 337503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 338503ad85cSMatthew Ahrens return (ret); 33915e6edf1Sgw } 340503ad85cSMatthew Ahrens return (B_FALSE); 34115e6edf1Sgw } 34215e6edf1Sgw 343c2a93d44Stimh /* 344f7170741SWill Andrews * Return non-zero if the spa version is less than requested version. 345c2a93d44Stimh */ 346da6c28aaSamw static int 3470a48a24eStimh zfs_earlier_version(const char *name, int version) 348da6c28aaSamw { 349da6c28aaSamw spa_t *spa; 350da6c28aaSamw 351da6c28aaSamw if (spa_open(name, &spa, FTAG) == 0) { 352da6c28aaSamw if (spa_version(spa) < version) { 353da6c28aaSamw spa_close(spa, FTAG); 354da6c28aaSamw return (1); 355da6c28aaSamw } 356da6c28aaSamw spa_close(spa, FTAG); 357da6c28aaSamw } 358da6c28aaSamw return (0); 359da6c28aaSamw } 360da6c28aaSamw 3619e6eda55Smarks /* 362745cd3c5Smaybee * Return TRUE if the ZPL version is less than requested version. 3639e6eda55Smarks */ 364745cd3c5Smaybee static boolean_t 365745cd3c5Smaybee zpl_earlier_version(const char *name, int version) 3669e6eda55Smarks { 3679e6eda55Smarks objset_t *os; 368745cd3c5Smaybee boolean_t rc = B_TRUE; 3699e6eda55Smarks 370503ad85cSMatthew Ahrens if (dmu_objset_hold(name, FTAG, &os) == 0) { 371745cd3c5Smaybee uint64_t zplversion; 3729e6eda55Smarks 373503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 374503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 375503ad85cSMatthew Ahrens return (B_TRUE); 376503ad85cSMatthew Ahrens } 377503ad85cSMatthew Ahrens /* XXX reading from non-owned objset */ 378745cd3c5Smaybee if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0) 379745cd3c5Smaybee rc = zplversion < version; 380503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 3819e6eda55Smarks } 3829e6eda55Smarks return (rc); 3839e6eda55Smarks } 3849e6eda55Smarks 385228975ccSek static void 386228975ccSek zfs_log_history(zfs_cmd_t *zc) 387228975ccSek { 388228975ccSek spa_t *spa; 389228975ccSek char *buf; 390ecd6cf80Smarks 391228975ccSek if ((buf = history_str_get(zc)) == NULL) 392228975ccSek return; 393228975ccSek 394228975ccSek if (spa_open(zc->zc_name, &spa, FTAG) == 0) { 395228975ccSek if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) 3964445fffbSMatthew Ahrens (void) spa_history_log(spa, buf); 397228975ccSek spa_close(spa, FTAG); 398228975ccSek } 399228975ccSek history_str_free(buf); 400ecd6cf80Smarks } 401ecd6cf80Smarks 402fa9e4066Sahrens /* 403fa9e4066Sahrens * Policy for top-level read operations (list pools). Requires no privileges, 404fa9e4066Sahrens * and can be used in the local zone, as there is no associated dataset. 405fa9e4066Sahrens */ 406fa9e4066Sahrens /* ARGSUSED */ 407fa9e4066Sahrens static int 4084445fffbSMatthew Ahrens zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 409fa9e4066Sahrens { 410fa9e4066Sahrens return (0); 411fa9e4066Sahrens } 412fa9e4066Sahrens 413fa9e4066Sahrens /* 414fa9e4066Sahrens * Policy for dataset read operations (list children, get statistics). Requires 415fa9e4066Sahrens * no privileges, but must be visible in the local zone. 416fa9e4066Sahrens */ 417fa9e4066Sahrens /* ARGSUSED */ 418fa9e4066Sahrens static int 4194445fffbSMatthew Ahrens zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 420fa9e4066Sahrens { 421fa9e4066Sahrens if (INGLOBALZONE(curproc) || 422ecd6cf80Smarks zone_dataset_visible(zc->zc_name, NULL)) 423fa9e4066Sahrens return (0); 424fa9e4066Sahrens 425be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 426fa9e4066Sahrens } 427fa9e4066Sahrens 428fa9e4066Sahrens static int 429a7f53a56SChris Kirby zfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr) 430fa9e4066Sahrens { 431fa9e4066Sahrens int writable = 1; 432fa9e4066Sahrens 433fa9e4066Sahrens /* 434fa9e4066Sahrens * The dataset must be visible by this zone -- check this first 435fa9e4066Sahrens * so they don't see EPERM on something they shouldn't know about. 436fa9e4066Sahrens */ 437fa9e4066Sahrens if (!INGLOBALZONE(curproc) && 438fa9e4066Sahrens !zone_dataset_visible(dataset, &writable)) 439be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 440fa9e4066Sahrens 441fa9e4066Sahrens if (INGLOBALZONE(curproc)) { 442fa9e4066Sahrens /* 443fa9e4066Sahrens * If the fs is zoned, only root can access it from the 444fa9e4066Sahrens * global zone. 445fa9e4066Sahrens */ 446fa9e4066Sahrens if (secpolicy_zfs(cr) && zoned) 447be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 448fa9e4066Sahrens } else { 449fa9e4066Sahrens /* 450fa9e4066Sahrens * If we are in a local zone, the 'zoned' property must be set. 451fa9e4066Sahrens */ 452fa9e4066Sahrens if (!zoned) 453be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 454fa9e4066Sahrens 455fa9e4066Sahrens /* must be writable by this zone */ 456fa9e4066Sahrens if (!writable) 457be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 458fa9e4066Sahrens } 459fa9e4066Sahrens return (0); 460fa9e4066Sahrens } 461fa9e4066Sahrens 462a7f53a56SChris Kirby static int 463a7f53a56SChris Kirby zfs_dozonecheck(const char *dataset, cred_t *cr) 464a7f53a56SChris Kirby { 465a7f53a56SChris Kirby uint64_t zoned; 466a7f53a56SChris Kirby 467a7f53a56SChris Kirby if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) 468be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 469a7f53a56SChris Kirby 470a7f53a56SChris Kirby return (zfs_dozonecheck_impl(dataset, zoned, cr)); 471a7f53a56SChris Kirby } 472a7f53a56SChris Kirby 473a7f53a56SChris Kirby static int 474a7f53a56SChris Kirby zfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr) 475a7f53a56SChris Kirby { 476a7f53a56SChris Kirby uint64_t zoned; 477a7f53a56SChris Kirby 4783b2aab18SMatthew Ahrens if (dsl_prop_get_int_ds(ds, "zoned", &zoned)) 479be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 480a7f53a56SChris Kirby 481a7f53a56SChris Kirby return (zfs_dozonecheck_impl(dataset, zoned, cr)); 482a7f53a56SChris Kirby } 483a7f53a56SChris Kirby 4844445fffbSMatthew Ahrens static int 4853b2aab18SMatthew Ahrens zfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds, 4863b2aab18SMatthew Ahrens const char *perm, cred_t *cr) 487fa9e4066Sahrens { 488fa9e4066Sahrens int error; 489fa9e4066Sahrens 49019b94df9SMatthew Ahrens error = zfs_dozonecheck_ds(name, ds, cr); 491ecd6cf80Smarks if (error == 0) { 492ecd6cf80Smarks error = secpolicy_zfs(cr); 4933b2aab18SMatthew Ahrens if (error != 0) 4944445fffbSMatthew Ahrens error = dsl_deleg_access_impl(ds, perm, cr); 495ecd6cf80Smarks } 496ecd6cf80Smarks return (error); 497ecd6cf80Smarks } 498ecd6cf80Smarks 4994445fffbSMatthew Ahrens static int 5003b2aab18SMatthew Ahrens zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) 501a7f53a56SChris Kirby { 502a7f53a56SChris Kirby int error; 5033b2aab18SMatthew Ahrens dsl_dataset_t *ds; 5043b2aab18SMatthew Ahrens dsl_pool_t *dp; 505a7f53a56SChris Kirby 50625f7d993SMatthew Ahrens /* 50725f7d993SMatthew Ahrens * First do a quick check for root in the global zone, which 50825f7d993SMatthew Ahrens * is allowed to do all write_perms. This ensures that zfs_ioc_* 50925f7d993SMatthew Ahrens * will get to handle nonexistent datasets. 51025f7d993SMatthew Ahrens */ 51125f7d993SMatthew Ahrens if (INGLOBALZONE(curproc) && secpolicy_zfs(cr) == 0) 51225f7d993SMatthew Ahrens return (0); 51325f7d993SMatthew Ahrens 5143b2aab18SMatthew Ahrens error = dsl_pool_hold(name, FTAG, &dp); 5153b2aab18SMatthew Ahrens if (error != 0) 5163b2aab18SMatthew Ahrens return (error); 5173b2aab18SMatthew Ahrens 5183b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, name, FTAG, &ds); 5193b2aab18SMatthew Ahrens if (error != 0) { 5203b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 5213b2aab18SMatthew Ahrens return (error); 522a7f53a56SChris Kirby } 5233b2aab18SMatthew Ahrens 5243b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms_ds(name, ds, perm, cr); 5253b2aab18SMatthew Ahrens 5263b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 5273b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 528a7f53a56SChris Kirby return (error); 529a7f53a56SChris Kirby } 530a7f53a56SChris Kirby 5314201a95eSRic Aleshire /* 5324201a95eSRic Aleshire * Policy for setting the security label property. 5334201a95eSRic Aleshire * 5344201a95eSRic Aleshire * Returns 0 for success, non-zero for access and other errors. 5354201a95eSRic Aleshire */ 5364201a95eSRic Aleshire static int 53792241e0bSTom Erickson zfs_set_slabel_policy(const char *name, char *strval, cred_t *cr) 5384201a95eSRic Aleshire { 5394201a95eSRic Aleshire char ds_hexsl[MAXNAMELEN]; 5404201a95eSRic Aleshire bslabel_t ds_sl, new_sl; 5414201a95eSRic Aleshire boolean_t new_default = FALSE; 5424201a95eSRic Aleshire uint64_t zoned; 5434201a95eSRic Aleshire int needed_priv = -1; 5444201a95eSRic Aleshire int error; 5454201a95eSRic Aleshire 5464201a95eSRic Aleshire /* First get the existing dataset label. */ 5474201a95eSRic Aleshire error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 5484201a95eSRic Aleshire 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 5493b2aab18SMatthew Ahrens if (error != 0) 550be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5514201a95eSRic Aleshire 5524201a95eSRic Aleshire if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0) 5534201a95eSRic Aleshire new_default = TRUE; 5544201a95eSRic Aleshire 5554201a95eSRic Aleshire /* The label must be translatable */ 5564201a95eSRic Aleshire if (!new_default && (hexstr_to_label(strval, &new_sl) != 0)) 557be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5584201a95eSRic Aleshire 5594201a95eSRic Aleshire /* 5604201a95eSRic Aleshire * In a non-global zone, disallow attempts to set a label that 5614201a95eSRic Aleshire * doesn't match that of the zone; otherwise no other checks 5624201a95eSRic Aleshire * are needed. 5634201a95eSRic Aleshire */ 5644201a95eSRic Aleshire if (!INGLOBALZONE(curproc)) { 5654201a95eSRic Aleshire if (new_default || !blequal(&new_sl, CR_SL(CRED()))) 566be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5674201a95eSRic Aleshire return (0); 5684201a95eSRic Aleshire } 5694201a95eSRic Aleshire 5704201a95eSRic Aleshire /* 5714201a95eSRic Aleshire * For global-zone datasets (i.e., those whose zoned property is 5724201a95eSRic Aleshire * "off", verify that the specified new label is valid for the 5734201a95eSRic Aleshire * global zone. 5744201a95eSRic Aleshire */ 5754201a95eSRic Aleshire if (dsl_prop_get_integer(name, 5764201a95eSRic Aleshire zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) 577be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5784201a95eSRic Aleshire if (!zoned) { 5794201a95eSRic Aleshire if (zfs_check_global_label(name, strval) != 0) 580be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 5814201a95eSRic Aleshire } 5824201a95eSRic Aleshire 5834201a95eSRic Aleshire /* 5844201a95eSRic Aleshire * If the existing dataset label is nondefault, check if the 5854201a95eSRic Aleshire * dataset is mounted (label cannot be changed while mounted). 5864201a95eSRic Aleshire * Get the zfsvfs; if there isn't one, then the dataset isn't 5874201a95eSRic Aleshire * mounted (or isn't a dataset, doesn't exist, ...). 5884201a95eSRic Aleshire */ 5894201a95eSRic Aleshire if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) { 59092241e0bSTom Erickson objset_t *os; 59192241e0bSTom Erickson static char *setsl_tag = "setsl_tag"; 59292241e0bSTom Erickson 5934201a95eSRic Aleshire /* 5944201a95eSRic Aleshire * Try to own the dataset; abort if there is any error, 5954201a95eSRic Aleshire * (e.g., already mounted, in use, or other error). 5964201a95eSRic Aleshire */ 597*eb633035STom Caputi error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE, B_TRUE, 59892241e0bSTom Erickson setsl_tag, &os); 5993b2aab18SMatthew Ahrens if (error != 0) 600be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 6014201a95eSRic Aleshire 602*eb633035STom Caputi dmu_objset_disown(os, B_TRUE, setsl_tag); 60392241e0bSTom Erickson 6044201a95eSRic Aleshire if (new_default) { 6054201a95eSRic Aleshire needed_priv = PRIV_FILE_DOWNGRADE_SL; 6064201a95eSRic Aleshire goto out_check; 6074201a95eSRic Aleshire } 6084201a95eSRic Aleshire 6094201a95eSRic Aleshire if (hexstr_to_label(strval, &new_sl) != 0) 610be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 6114201a95eSRic Aleshire 6124201a95eSRic Aleshire if (blstrictdom(&ds_sl, &new_sl)) 6134201a95eSRic Aleshire needed_priv = PRIV_FILE_DOWNGRADE_SL; 6144201a95eSRic Aleshire else if (blstrictdom(&new_sl, &ds_sl)) 6154201a95eSRic Aleshire needed_priv = PRIV_FILE_UPGRADE_SL; 6164201a95eSRic Aleshire } else { 6174201a95eSRic Aleshire /* dataset currently has a default label */ 6184201a95eSRic Aleshire if (!new_default) 6194201a95eSRic Aleshire needed_priv = PRIV_FILE_UPGRADE_SL; 6204201a95eSRic Aleshire } 6214201a95eSRic Aleshire 6224201a95eSRic Aleshire out_check: 6234201a95eSRic Aleshire if (needed_priv != -1) 6244201a95eSRic Aleshire return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL)); 6254201a95eSRic Aleshire return (0); 6264201a95eSRic Aleshire } 6274201a95eSRic Aleshire 628ecd6cf80Smarks static int 62992241e0bSTom Erickson zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval, 63092241e0bSTom Erickson cred_t *cr) 631ecd6cf80Smarks { 63292241e0bSTom Erickson char *strval; 63392241e0bSTom Erickson 634ecd6cf80Smarks /* 635ecd6cf80Smarks * Check permissions for special properties. 636ecd6cf80Smarks */ 637ecd6cf80Smarks switch (prop) { 638ecd6cf80Smarks case ZFS_PROP_ZONED: 639ecd6cf80Smarks /* 640ecd6cf80Smarks * Disallow setting of 'zoned' from within a local zone. 641ecd6cf80Smarks */ 642ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 643be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 644ecd6cf80Smarks break; 645ecd6cf80Smarks 646ecd6cf80Smarks case ZFS_PROP_QUOTA: 647a2afb611SJerry Jelinek case ZFS_PROP_FILESYSTEM_LIMIT: 648a2afb611SJerry Jelinek case ZFS_PROP_SNAPSHOT_LIMIT: 649ecd6cf80Smarks if (!INGLOBALZONE(curproc)) { 650ecd6cf80Smarks uint64_t zoned; 6519adfa60dSMatthew Ahrens char setpoint[ZFS_MAX_DATASET_NAME_LEN]; 652ecd6cf80Smarks /* 653ecd6cf80Smarks * Unprivileged users are allowed to modify the 654a2afb611SJerry Jelinek * limit on things *under* (ie. contained by) 655ecd6cf80Smarks * the thing they own. 656ecd6cf80Smarks */ 65792241e0bSTom Erickson if (dsl_prop_get_integer(dsname, "zoned", &zoned, 658ecd6cf80Smarks setpoint)) 659be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 66092241e0bSTom Erickson if (!zoned || strlen(dsname) <= strlen(setpoint)) 661be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 662ecd6cf80Smarks } 663db870a07Sahrens break; 6644201a95eSRic Aleshire 6654201a95eSRic Aleshire case ZFS_PROP_MLSLABEL: 6664201a95eSRic Aleshire if (!is_system_labeled()) 667be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 66892241e0bSTom Erickson 66992241e0bSTom Erickson if (nvpair_value_string(propval, &strval) == 0) { 67092241e0bSTom Erickson int err; 67192241e0bSTom Erickson 67292241e0bSTom Erickson err = zfs_set_slabel_policy(dsname, strval, CRED()); 67392241e0bSTom Erickson if (err != 0) 67492241e0bSTom Erickson return (err); 67592241e0bSTom Erickson } 6764201a95eSRic Aleshire break; 677ecd6cf80Smarks } 678ecd6cf80Smarks 67992241e0bSTom Erickson return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr)); 680ecd6cf80Smarks } 681ecd6cf80Smarks 6824445fffbSMatthew Ahrens /* ARGSUSED */ 6834445fffbSMatthew Ahrens static int 6844445fffbSMatthew Ahrens zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 685ecd6cf80Smarks { 686ecd6cf80Smarks int error; 687ecd6cf80Smarks 688ecd6cf80Smarks error = zfs_dozonecheck(zc->zc_name, cr); 6893b2aab18SMatthew Ahrens if (error != 0) 690fa9e4066Sahrens return (error); 691fa9e4066Sahrens 692ecd6cf80Smarks /* 693ecd6cf80Smarks * permission to set permissions will be evaluated later in 694ecd6cf80Smarks * dsl_deleg_can_allow() 695ecd6cf80Smarks */ 696ecd6cf80Smarks return (0); 697ecd6cf80Smarks } 698ecd6cf80Smarks 6994445fffbSMatthew Ahrens /* ARGSUSED */ 7004445fffbSMatthew Ahrens static int 7014445fffbSMatthew Ahrens zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 702ecd6cf80Smarks { 703681d9761SEric Taylor return (zfs_secpolicy_write_perms(zc->zc_name, 704681d9761SEric Taylor ZFS_DELEG_PERM_ROLLBACK, cr)); 705ecd6cf80Smarks } 706ecd6cf80Smarks 7074445fffbSMatthew Ahrens /* ARGSUSED */ 7084445fffbSMatthew Ahrens static int 7094445fffbSMatthew Ahrens zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 710ecd6cf80Smarks { 711a7f53a56SChris Kirby dsl_pool_t *dp; 712a7f53a56SChris Kirby dsl_dataset_t *ds; 713a7f53a56SChris Kirby char *cp; 714a7f53a56SChris Kirby int error; 715a7f53a56SChris Kirby 716a7f53a56SChris Kirby /* 717a7f53a56SChris Kirby * Generate the current snapshot name from the given objsetid, then 718a7f53a56SChris Kirby * use that name for the secpolicy/zone checks. 719a7f53a56SChris Kirby */ 720a7f53a56SChris Kirby cp = strchr(zc->zc_name, '@'); 721a7f53a56SChris Kirby if (cp == NULL) 722be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 7233b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 7243b2aab18SMatthew Ahrens if (error != 0) 725a7f53a56SChris Kirby return (error); 726a7f53a56SChris Kirby 727a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds); 7283b2aab18SMatthew Ahrens if (error != 0) { 7293b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 730a7f53a56SChris Kirby return (error); 7313b2aab18SMatthew Ahrens } 732a7f53a56SChris Kirby 733a7f53a56SChris Kirby dsl_dataset_name(ds, zc->zc_name); 734a7f53a56SChris Kirby 735a7f53a56SChris Kirby error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds, 736a7f53a56SChris Kirby ZFS_DELEG_PERM_SEND, cr); 737a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 7383b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 739a7f53a56SChris Kirby 740a7f53a56SChris Kirby return (error); 741ecd6cf80Smarks } 742ecd6cf80Smarks 7434445fffbSMatthew Ahrens /* ARGSUSED */ 744743a77edSAlan Wright static int 7454445fffbSMatthew Ahrens zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 7464445fffbSMatthew Ahrens { 7474445fffbSMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 7484445fffbSMatthew Ahrens ZFS_DELEG_PERM_SEND, cr)); 7494445fffbSMatthew Ahrens } 7504445fffbSMatthew Ahrens 7514445fffbSMatthew Ahrens /* ARGSUSED */ 7524445fffbSMatthew Ahrens static int 7534445fffbSMatthew Ahrens zfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 754743a77edSAlan Wright { 755743a77edSAlan Wright vnode_t *vp; 756743a77edSAlan Wright int error; 757743a77edSAlan Wright 758743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 759743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 760743a77edSAlan Wright return (error); 761743a77edSAlan Wright 762743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 763743a77edSAlan Wright 764743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 765743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 766743a77edSAlan Wright zc->zc_name) != 0)) { 767743a77edSAlan Wright VN_RELE(vp); 768be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 769743a77edSAlan Wright } 770743a77edSAlan Wright 771743a77edSAlan Wright VN_RELE(vp); 772743a77edSAlan Wright return (dsl_deleg_access(zc->zc_name, 773743a77edSAlan Wright ZFS_DELEG_PERM_SHARE, cr)); 774743a77edSAlan Wright } 775743a77edSAlan Wright 776ecd6cf80Smarks int 7774445fffbSMatthew Ahrens zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 778ecd6cf80Smarks { 779ecd6cf80Smarks if (!INGLOBALZONE(curproc)) 780be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 781ecd6cf80Smarks 7823cb34c60Sahrens if (secpolicy_nfs(cr) == 0) { 783ecd6cf80Smarks return (0); 784ecd6cf80Smarks } else { 7854445fffbSMatthew Ahrens return (zfs_secpolicy_deleg_share(zc, innvl, cr)); 786743a77edSAlan Wright } 787743a77edSAlan Wright } 788ecd6cf80Smarks 789743a77edSAlan Wright int 7904445fffbSMatthew Ahrens zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 791743a77edSAlan Wright { 792743a77edSAlan Wright if (!INGLOBALZONE(curproc)) 793be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 794ecd6cf80Smarks 795743a77edSAlan Wright if (secpolicy_smb(cr) == 0) { 796743a77edSAlan Wright return (0); 797743a77edSAlan Wright } else { 7984445fffbSMatthew Ahrens return (zfs_secpolicy_deleg_share(zc, innvl, cr)); 799ecd6cf80Smarks } 800fa9e4066Sahrens } 801fa9e4066Sahrens 802fa9e4066Sahrens static int 803ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize) 804fa9e4066Sahrens { 805fa9e4066Sahrens char *cp; 806fa9e4066Sahrens 807fa9e4066Sahrens /* 808fa9e4066Sahrens * Remove the @bla or /bla from the end of the name to get the parent. 809fa9e4066Sahrens */ 810ecd6cf80Smarks (void) strncpy(parent, datasetname, parentsize); 811ecd6cf80Smarks cp = strrchr(parent, '@'); 812fa9e4066Sahrens if (cp != NULL) { 813fa9e4066Sahrens cp[0] = '\0'; 814fa9e4066Sahrens } else { 815ecd6cf80Smarks cp = strrchr(parent, '/'); 816fa9e4066Sahrens if (cp == NULL) 817be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 818fa9e4066Sahrens cp[0] = '\0'; 819ecd6cf80Smarks } 820ecd6cf80Smarks 821ecd6cf80Smarks return (0); 822ecd6cf80Smarks } 823ecd6cf80Smarks 824ecd6cf80Smarks int 825ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) 826ecd6cf80Smarks { 827ecd6cf80Smarks int error; 828ecd6cf80Smarks 829ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(name, 830ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 831ecd6cf80Smarks return (error); 832ecd6cf80Smarks 833ecd6cf80Smarks return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); 834ecd6cf80Smarks } 835ecd6cf80Smarks 8364445fffbSMatthew Ahrens /* ARGSUSED */ 837ecd6cf80Smarks static int 8384445fffbSMatthew Ahrens zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 839ecd6cf80Smarks { 840ecd6cf80Smarks return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); 841ecd6cf80Smarks } 842ecd6cf80Smarks 843cbf6f6aaSWilliam Gorrell /* 844cbf6f6aaSWilliam Gorrell * Destroying snapshots with delegated permissions requires 8454445fffbSMatthew Ahrens * descendant mount and destroy permissions. 846cbf6f6aaSWilliam Gorrell */ 8474445fffbSMatthew Ahrens /* ARGSUSED */ 848cbf6f6aaSWilliam Gorrell static int 8494445fffbSMatthew Ahrens zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 850cbf6f6aaSWilliam Gorrell { 8514445fffbSMatthew Ahrens nvlist_t *snaps; 8524445fffbSMatthew Ahrens nvpair_t *pair, *nextpair; 8534445fffbSMatthew Ahrens int error = 0; 854cbf6f6aaSWilliam Gorrell 8554445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 856be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 8574445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 8584445fffbSMatthew Ahrens pair = nextpair) { 8594445fffbSMatthew Ahrens nextpair = nvlist_next_nvpair(snaps, pair); 86078f17100SMatthew Ahrens error = zfs_secpolicy_destroy_perms(nvpair_name(pair), cr); 86178f17100SMatthew Ahrens if (error == ENOENT) { 8624445fffbSMatthew Ahrens /* 8634445fffbSMatthew Ahrens * Ignore any snapshots that don't exist (we consider 8644445fffbSMatthew Ahrens * them "already destroyed"). Remove the name from the 8654445fffbSMatthew Ahrens * nvl here in case the snapshot is created between 8664445fffbSMatthew Ahrens * now and when we try to destroy it (in which case 8674445fffbSMatthew Ahrens * we don't want to destroy it since we haven't 8684445fffbSMatthew Ahrens * checked for permission). 8694445fffbSMatthew Ahrens */ 8704445fffbSMatthew Ahrens fnvlist_remove_nvpair(snaps, pair); 8714445fffbSMatthew Ahrens error = 0; 8724445fffbSMatthew Ahrens } 8734445fffbSMatthew Ahrens if (error != 0) 8744445fffbSMatthew Ahrens break; 8754445fffbSMatthew Ahrens } 876cbf6f6aaSWilliam Gorrell 877cbf6f6aaSWilliam Gorrell return (error); 878cbf6f6aaSWilliam Gorrell } 879cbf6f6aaSWilliam Gorrell 880ecd6cf80Smarks int 881ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) 882ecd6cf80Smarks { 8839adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 884ecd6cf80Smarks int error; 885ecd6cf80Smarks 886ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 887ecd6cf80Smarks ZFS_DELEG_PERM_RENAME, cr)) != 0) 888ecd6cf80Smarks return (error); 889ecd6cf80Smarks 890ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(from, 891ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 892ecd6cf80Smarks return (error); 893ecd6cf80Smarks 894ecd6cf80Smarks if ((error = zfs_get_parent(to, parentname, 895ecd6cf80Smarks sizeof (parentname))) != 0) 896ecd6cf80Smarks return (error); 897ecd6cf80Smarks 898ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 899ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 900ecd6cf80Smarks return (error); 901ecd6cf80Smarks 902ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 903ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 904ecd6cf80Smarks return (error); 905ecd6cf80Smarks 906ecd6cf80Smarks return (error); 907ecd6cf80Smarks } 908ecd6cf80Smarks 9094445fffbSMatthew Ahrens /* ARGSUSED */ 910ecd6cf80Smarks static int 9114445fffbSMatthew Ahrens zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 912ecd6cf80Smarks { 913ecd6cf80Smarks return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); 914ecd6cf80Smarks } 915ecd6cf80Smarks 9164445fffbSMatthew Ahrens /* ARGSUSED */ 917ecd6cf80Smarks static int 9184445fffbSMatthew Ahrens zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 919ecd6cf80Smarks { 9203b2aab18SMatthew Ahrens dsl_pool_t *dp; 9213b2aab18SMatthew Ahrens dsl_dataset_t *clone; 922ecd6cf80Smarks int error; 923ecd6cf80Smarks 924ecd6cf80Smarks error = zfs_secpolicy_write_perms(zc->zc_name, 925ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 9263b2aab18SMatthew Ahrens if (error != 0) 9273b2aab18SMatthew Ahrens return (error); 9283b2aab18SMatthew Ahrens 9293b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 9303b2aab18SMatthew Ahrens if (error != 0) 931ecd6cf80Smarks return (error); 932ecd6cf80Smarks 9333b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &clone); 934ecd6cf80Smarks 935ecd6cf80Smarks if (error == 0) { 9369adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 9373b2aab18SMatthew Ahrens dsl_dataset_t *origin = NULL; 938ecd6cf80Smarks dsl_dir_t *dd; 9393b2aab18SMatthew Ahrens dd = clone->ds_dir; 940ecd6cf80Smarks 941745cd3c5Smaybee error = dsl_dataset_hold_obj(dd->dd_pool, 942c1379625SJustin T. Gibbs dsl_dir_phys(dd)->dd_origin_obj, FTAG, &origin); 9433b2aab18SMatthew Ahrens if (error != 0) { 9443b2aab18SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 9453b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 946ecd6cf80Smarks return (error); 947ecd6cf80Smarks } 948ecd6cf80Smarks 9493b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms_ds(zc->zc_name, clone, 950ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr); 951ecd6cf80Smarks 9523b2aab18SMatthew Ahrens dsl_dataset_name(origin, parentname); 9533b2aab18SMatthew Ahrens if (error == 0) { 9543b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms_ds(parentname, origin, 955ecd6cf80Smarks ZFS_DELEG_PERM_PROMOTE, cr); 9563b2aab18SMatthew Ahrens } 9573b2aab18SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 9583b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 959ecd6cf80Smarks } 9603b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 961ecd6cf80Smarks return (error); 962ecd6cf80Smarks } 963ecd6cf80Smarks 9644445fffbSMatthew Ahrens /* ARGSUSED */ 965ecd6cf80Smarks static int 9664445fffbSMatthew Ahrens zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 967ecd6cf80Smarks { 968ecd6cf80Smarks int error; 969ecd6cf80Smarks 970ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 971ecd6cf80Smarks ZFS_DELEG_PERM_RECEIVE, cr)) != 0) 972ecd6cf80Smarks return (error); 973ecd6cf80Smarks 974ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(zc->zc_name, 975ecd6cf80Smarks ZFS_DELEG_PERM_MOUNT, cr)) != 0) 976ecd6cf80Smarks return (error); 977ecd6cf80Smarks 978ecd6cf80Smarks return (zfs_secpolicy_write_perms(zc->zc_name, 979ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)); 980ecd6cf80Smarks } 981ecd6cf80Smarks 982ecd6cf80Smarks int 983ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) 984ecd6cf80Smarks { 985681d9761SEric Taylor return (zfs_secpolicy_write_perms(name, 986681d9761SEric Taylor ZFS_DELEG_PERM_SNAPSHOT, cr)); 987ecd6cf80Smarks } 988ecd6cf80Smarks 9894445fffbSMatthew Ahrens /* 9904445fffbSMatthew Ahrens * Check for permission to create each snapshot in the nvlist. 9914445fffbSMatthew Ahrens */ 9924445fffbSMatthew Ahrens /* ARGSUSED */ 993ecd6cf80Smarks static int 9944445fffbSMatthew Ahrens zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 995ecd6cf80Smarks { 9964445fffbSMatthew Ahrens nvlist_t *snaps; 997d5285caeSGeorge Wilson int error = 0; 9984445fffbSMatthew Ahrens nvpair_t *pair; 999ecd6cf80Smarks 10004445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 1001be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 10024445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 10034445fffbSMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 10044445fffbSMatthew Ahrens char *name = nvpair_name(pair); 10054445fffbSMatthew Ahrens char *atp = strchr(name, '@'); 10064445fffbSMatthew Ahrens 10074445fffbSMatthew Ahrens if (atp == NULL) { 1008be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 10094445fffbSMatthew Ahrens break; 10104445fffbSMatthew Ahrens } 10114445fffbSMatthew Ahrens *atp = '\0'; 10124445fffbSMatthew Ahrens error = zfs_secpolicy_snapshot_perms(name, cr); 10134445fffbSMatthew Ahrens *atp = '@'; 10144445fffbSMatthew Ahrens if (error != 0) 10154445fffbSMatthew Ahrens break; 10164445fffbSMatthew Ahrens } 10174445fffbSMatthew Ahrens return (error); 1018ecd6cf80Smarks } 1019ecd6cf80Smarks 102078f17100SMatthew Ahrens /* 102178f17100SMatthew Ahrens * Check for permission to create each snapshot in the nvlist. 102278f17100SMatthew Ahrens */ 102378f17100SMatthew Ahrens /* ARGSUSED */ 102478f17100SMatthew Ahrens static int 102578f17100SMatthew Ahrens zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 102678f17100SMatthew Ahrens { 102778f17100SMatthew Ahrens int error = 0; 102878f17100SMatthew Ahrens 102978f17100SMatthew Ahrens for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL); 103078f17100SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) { 103178f17100SMatthew Ahrens char *name = nvpair_name(pair); 103278f17100SMatthew Ahrens char *hashp = strchr(name, '#'); 103378f17100SMatthew Ahrens 103478f17100SMatthew Ahrens if (hashp == NULL) { 103578f17100SMatthew Ahrens error = SET_ERROR(EINVAL); 103678f17100SMatthew Ahrens break; 103778f17100SMatthew Ahrens } 103878f17100SMatthew Ahrens *hashp = '\0'; 103978f17100SMatthew Ahrens error = zfs_secpolicy_write_perms(name, 104078f17100SMatthew Ahrens ZFS_DELEG_PERM_BOOKMARK, cr); 104178f17100SMatthew Ahrens *hashp = '#'; 104278f17100SMatthew Ahrens if (error != 0) 104378f17100SMatthew Ahrens break; 104478f17100SMatthew Ahrens } 104578f17100SMatthew Ahrens return (error); 104678f17100SMatthew Ahrens } 104778f17100SMatthew Ahrens 10485cabbc6bSPrashanth Sreenivasa /* ARGSUSED */ 10495cabbc6bSPrashanth Sreenivasa static int 10505cabbc6bSPrashanth Sreenivasa zfs_secpolicy_remap(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 10515cabbc6bSPrashanth Sreenivasa { 10525cabbc6bSPrashanth Sreenivasa return (zfs_secpolicy_write_perms(zc->zc_name, 10535cabbc6bSPrashanth Sreenivasa ZFS_DELEG_PERM_REMAP, cr)); 10545cabbc6bSPrashanth Sreenivasa } 10555cabbc6bSPrashanth Sreenivasa 105678f17100SMatthew Ahrens /* ARGSUSED */ 105778f17100SMatthew Ahrens static int 105878f17100SMatthew Ahrens zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 105978f17100SMatthew Ahrens { 106078f17100SMatthew Ahrens nvpair_t *pair, *nextpair; 106178f17100SMatthew Ahrens int error = 0; 106278f17100SMatthew Ahrens 106378f17100SMatthew Ahrens for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL; 106478f17100SMatthew Ahrens pair = nextpair) { 106578f17100SMatthew Ahrens char *name = nvpair_name(pair); 106678f17100SMatthew Ahrens char *hashp = strchr(name, '#'); 106778f17100SMatthew Ahrens nextpair = nvlist_next_nvpair(innvl, pair); 106878f17100SMatthew Ahrens 106978f17100SMatthew Ahrens if (hashp == NULL) { 107078f17100SMatthew Ahrens error = SET_ERROR(EINVAL); 107178f17100SMatthew Ahrens break; 107278f17100SMatthew Ahrens } 107378f17100SMatthew Ahrens 107478f17100SMatthew Ahrens *hashp = '\0'; 107578f17100SMatthew Ahrens error = zfs_secpolicy_write_perms(name, 107678f17100SMatthew Ahrens ZFS_DELEG_PERM_DESTROY, cr); 107778f17100SMatthew Ahrens *hashp = '#'; 107878f17100SMatthew Ahrens if (error == ENOENT) { 107978f17100SMatthew Ahrens /* 108078f17100SMatthew Ahrens * Ignore any filesystems that don't exist (we consider 108178f17100SMatthew Ahrens * their bookmarks "already destroyed"). Remove 108278f17100SMatthew Ahrens * the name from the nvl here in case the filesystem 108378f17100SMatthew Ahrens * is created between now and when we try to destroy 108478f17100SMatthew Ahrens * the bookmark (in which case we don't want to 108578f17100SMatthew Ahrens * destroy it since we haven't checked for permission). 108678f17100SMatthew Ahrens */ 108778f17100SMatthew Ahrens fnvlist_remove_nvpair(innvl, pair); 108878f17100SMatthew Ahrens error = 0; 108978f17100SMatthew Ahrens } 109078f17100SMatthew Ahrens if (error != 0) 109178f17100SMatthew Ahrens break; 109278f17100SMatthew Ahrens } 109378f17100SMatthew Ahrens 109478f17100SMatthew Ahrens return (error); 109578f17100SMatthew Ahrens } 109678f17100SMatthew Ahrens 10974445fffbSMatthew Ahrens /* ARGSUSED */ 1098ecd6cf80Smarks static int 10994445fffbSMatthew Ahrens zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 11004445fffbSMatthew Ahrens { 11014445fffbSMatthew Ahrens /* 11024445fffbSMatthew Ahrens * Even root must have a proper TSD so that we know what pool 11034445fffbSMatthew Ahrens * to log to. 11044445fffbSMatthew Ahrens */ 11054445fffbSMatthew Ahrens if (tsd_get(zfs_allow_log_key) == NULL) 1106be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 11074445fffbSMatthew Ahrens return (0); 11084445fffbSMatthew Ahrens } 11094445fffbSMatthew Ahrens 11104445fffbSMatthew Ahrens static int 11114445fffbSMatthew Ahrens zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1112ecd6cf80Smarks { 11139adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 111492241e0bSTom Erickson int error; 11154445fffbSMatthew Ahrens char *origin; 1116ecd6cf80Smarks 1117ecd6cf80Smarks if ((error = zfs_get_parent(zc->zc_name, parentname, 1118ecd6cf80Smarks sizeof (parentname))) != 0) 1119ecd6cf80Smarks return (error); 1120fa9e4066Sahrens 11214445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "origin", &origin) == 0 && 11224445fffbSMatthew Ahrens (error = zfs_secpolicy_write_perms(origin, 11234445fffbSMatthew Ahrens ZFS_DELEG_PERM_CLONE, cr)) != 0) 11244445fffbSMatthew Ahrens return (error); 1125fa9e4066Sahrens 1126ecd6cf80Smarks if ((error = zfs_secpolicy_write_perms(parentname, 1127ecd6cf80Smarks ZFS_DELEG_PERM_CREATE, cr)) != 0) 1128ecd6cf80Smarks return (error); 1129ecd6cf80Smarks 11304445fffbSMatthew Ahrens return (zfs_secpolicy_write_perms(parentname, 11314445fffbSMatthew Ahrens ZFS_DELEG_PERM_MOUNT, cr)); 1132fa9e4066Sahrens } 1133fa9e4066Sahrens 1134fa9e4066Sahrens /* 1135fa9e4066Sahrens * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 1136fa9e4066Sahrens * SYS_CONFIG privilege, which is not available in a local zone. 1137fa9e4066Sahrens */ 1138fa9e4066Sahrens /* ARGSUSED */ 1139fa9e4066Sahrens static int 11404445fffbSMatthew Ahrens zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1141fa9e4066Sahrens { 1142fa9e4066Sahrens if (secpolicy_sys_config(cr, B_FALSE) != 0) 1143be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 1144fa9e4066Sahrens 1145fa9e4066Sahrens return (0); 1146fa9e4066Sahrens } 1147fa9e4066Sahrens 114899d5e173STim Haley /* 114999d5e173STim Haley * Policy for object to name lookups. 115099d5e173STim Haley */ 115199d5e173STim Haley /* ARGSUSED */ 115299d5e173STim Haley static int 11534445fffbSMatthew Ahrens zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 115499d5e173STim Haley { 115599d5e173STim Haley int error; 115699d5e173STim Haley 115799d5e173STim Haley if ((error = secpolicy_sys_config(cr, B_FALSE)) == 0) 115899d5e173STim Haley return (0); 115999d5e173STim Haley 116099d5e173STim Haley error = zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_DIFF, cr); 116199d5e173STim Haley return (error); 116299d5e173STim Haley } 116399d5e173STim Haley 1164ea8dc4b6Seschrock /* 1165ea8dc4b6Seschrock * Policy for fault injection. Requires all privileges. 1166ea8dc4b6Seschrock */ 1167ea8dc4b6Seschrock /* ARGSUSED */ 1168ea8dc4b6Seschrock static int 11694445fffbSMatthew Ahrens zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1170ea8dc4b6Seschrock { 1171ea8dc4b6Seschrock return (secpolicy_zinject(cr)); 1172ea8dc4b6Seschrock } 1173ea8dc4b6Seschrock 11744445fffbSMatthew Ahrens /* ARGSUSED */ 1175e45ce728Sahrens static int 11764445fffbSMatthew Ahrens zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1177e45ce728Sahrens { 1178e45ce728Sahrens zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); 1179e45ce728Sahrens 1180990b4856Slling if (prop == ZPROP_INVAL) { 1181e45ce728Sahrens if (!zfs_prop_user(zc->zc_value)) 1182be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1183e45ce728Sahrens return (zfs_secpolicy_write_perms(zc->zc_name, 1184e45ce728Sahrens ZFS_DELEG_PERM_USERPROP, cr)); 1185e45ce728Sahrens } else { 118692241e0bSTom Erickson return (zfs_secpolicy_setprop(zc->zc_name, prop, 118792241e0bSTom Erickson NULL, cr)); 1188e45ce728Sahrens } 1189e45ce728Sahrens } 1190e45ce728Sahrens 119114843421SMatthew Ahrens static int 11924445fffbSMatthew Ahrens zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 119314843421SMatthew Ahrens { 11944445fffbSMatthew Ahrens int err = zfs_secpolicy_read(zc, innvl, cr); 119514843421SMatthew Ahrens if (err) 119614843421SMatthew Ahrens return (err); 119714843421SMatthew Ahrens 119814843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 1199be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 120014843421SMatthew Ahrens 120114843421SMatthew Ahrens if (zc->zc_value[0] == 0) { 120214843421SMatthew Ahrens /* 120314843421SMatthew Ahrens * They are asking about a posix uid/gid. If it's 120414843421SMatthew Ahrens * themself, allow it. 120514843421SMatthew Ahrens */ 120614843421SMatthew Ahrens if (zc->zc_objset_type == ZFS_PROP_USERUSED || 120714843421SMatthew Ahrens zc->zc_objset_type == ZFS_PROP_USERQUOTA) { 120814843421SMatthew Ahrens if (zc->zc_guid == crgetuid(cr)) 120914843421SMatthew Ahrens return (0); 121014843421SMatthew Ahrens } else { 121114843421SMatthew Ahrens if (groupmember(zc->zc_guid, cr)) 121214843421SMatthew Ahrens return (0); 121314843421SMatthew Ahrens } 121414843421SMatthew Ahrens } 121514843421SMatthew Ahrens 121614843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 121714843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 121814843421SMatthew Ahrens } 121914843421SMatthew Ahrens 122014843421SMatthew Ahrens static int 12214445fffbSMatthew Ahrens zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 122214843421SMatthew Ahrens { 12234445fffbSMatthew Ahrens int err = zfs_secpolicy_read(zc, innvl, cr); 122414843421SMatthew Ahrens if (err) 122514843421SMatthew Ahrens return (err); 122614843421SMatthew Ahrens 122714843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 1228be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 122914843421SMatthew Ahrens 123014843421SMatthew Ahrens return (zfs_secpolicy_write_perms(zc->zc_name, 123114843421SMatthew Ahrens userquota_perms[zc->zc_objset_type], cr)); 123214843421SMatthew Ahrens } 123314843421SMatthew Ahrens 12344445fffbSMatthew Ahrens /* ARGSUSED */ 123514843421SMatthew Ahrens static int 12364445fffbSMatthew Ahrens zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 123714843421SMatthew Ahrens { 123892241e0bSTom Erickson return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, 123992241e0bSTom Erickson NULL, cr)); 124014843421SMatthew Ahrens } 124114843421SMatthew Ahrens 12424445fffbSMatthew Ahrens /* ARGSUSED */ 1243842727c2SChris Kirby static int 12444445fffbSMatthew Ahrens zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1245842727c2SChris Kirby { 12463b2aab18SMatthew Ahrens nvpair_t *pair; 12473b2aab18SMatthew Ahrens nvlist_t *holds; 12483b2aab18SMatthew Ahrens int error; 12493b2aab18SMatthew Ahrens 12503b2aab18SMatthew Ahrens error = nvlist_lookup_nvlist(innvl, "holds", &holds); 12513b2aab18SMatthew Ahrens if (error != 0) 1252be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 12533b2aab18SMatthew Ahrens 12543b2aab18SMatthew Ahrens for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; 12553b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(holds, pair)) { 12569adfa60dSMatthew Ahrens char fsname[ZFS_MAX_DATASET_NAME_LEN]; 12573b2aab18SMatthew Ahrens error = dmu_fsname(nvpair_name(pair), fsname); 12583b2aab18SMatthew Ahrens if (error != 0) 12593b2aab18SMatthew Ahrens return (error); 12603b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms(fsname, 12613b2aab18SMatthew Ahrens ZFS_DELEG_PERM_HOLD, cr); 12623b2aab18SMatthew Ahrens if (error != 0) 12633b2aab18SMatthew Ahrens return (error); 12643b2aab18SMatthew Ahrens } 12653b2aab18SMatthew Ahrens return (0); 1266842727c2SChris Kirby } 1267842727c2SChris Kirby 12684445fffbSMatthew Ahrens /* ARGSUSED */ 1269842727c2SChris Kirby static int 12704445fffbSMatthew Ahrens zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1271842727c2SChris Kirby { 12723b2aab18SMatthew Ahrens nvpair_t *pair; 12733b2aab18SMatthew Ahrens int error; 12743b2aab18SMatthew Ahrens 12753b2aab18SMatthew Ahrens for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL; 12763b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(innvl, pair)) { 12779adfa60dSMatthew Ahrens char fsname[ZFS_MAX_DATASET_NAME_LEN]; 12783b2aab18SMatthew Ahrens error = dmu_fsname(nvpair_name(pair), fsname); 12793b2aab18SMatthew Ahrens if (error != 0) 12803b2aab18SMatthew Ahrens return (error); 12813b2aab18SMatthew Ahrens error = zfs_secpolicy_write_perms(fsname, 12823b2aab18SMatthew Ahrens ZFS_DELEG_PERM_RELEASE, cr); 12833b2aab18SMatthew Ahrens if (error != 0) 12843b2aab18SMatthew Ahrens return (error); 12853b2aab18SMatthew Ahrens } 12863b2aab18SMatthew Ahrens return (0); 1287842727c2SChris Kirby } 1288842727c2SChris Kirby 1289*eb633035STom Caputi /* ARGSUSED */ 1290*eb633035STom Caputi static int 1291*eb633035STom Caputi zfs_secpolicy_load_key(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1292*eb633035STom Caputi { 1293*eb633035STom Caputi return (zfs_secpolicy_write_perms(zc->zc_name, 1294*eb633035STom Caputi ZFS_DELEG_PERM_LOAD_KEY, cr)); 1295*eb633035STom Caputi } 1296*eb633035STom Caputi 1297*eb633035STom Caputi /* ARGSUSED */ 1298*eb633035STom Caputi static int 1299*eb633035STom Caputi zfs_secpolicy_change_key(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 1300*eb633035STom Caputi { 1301*eb633035STom Caputi return (zfs_secpolicy_write_perms(zc->zc_name, 1302*eb633035STom Caputi ZFS_DELEG_PERM_CHANGE_KEY, cr)); 1303*eb633035STom Caputi } 1304*eb633035STom Caputi 130599d5e173STim Haley /* 130699d5e173STim Haley * Policy for allowing temporary snapshots to be taken or released 130799d5e173STim Haley */ 130899d5e173STim Haley static int 13094445fffbSMatthew Ahrens zfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) 131099d5e173STim Haley { 131199d5e173STim Haley /* 131299d5e173STim Haley * A temporary snapshot is the same as a snapshot, 131399d5e173STim Haley * hold, destroy and release all rolled into one. 131499d5e173STim Haley * Delegated diff alone is sufficient that we allow this. 131599d5e173STim Haley */ 131699d5e173STim Haley int error; 131799d5e173STim Haley 131899d5e173STim Haley if ((error = zfs_secpolicy_write_perms(zc->zc_name, 131999d5e173STim Haley ZFS_DELEG_PERM_DIFF, cr)) == 0) 132099d5e173STim Haley return (0); 132199d5e173STim Haley 13224445fffbSMatthew Ahrens error = zfs_secpolicy_snapshot_perms(zc->zc_name, cr); 13233b2aab18SMatthew Ahrens if (error == 0) 13244445fffbSMatthew Ahrens error = zfs_secpolicy_hold(zc, innvl, cr); 13253b2aab18SMatthew Ahrens if (error == 0) 13264445fffbSMatthew Ahrens error = zfs_secpolicy_release(zc, innvl, cr); 13273b2aab18SMatthew Ahrens if (error == 0) 13284445fffbSMatthew Ahrens error = zfs_secpolicy_destroy(zc, innvl, cr); 132999d5e173STim Haley return (error); 133099d5e173STim Haley } 133199d5e173STim Haley 1332fa9e4066Sahrens /* 1333fa9e4066Sahrens * Returns the nvlist as specified by the user in the zfs_cmd_t. 1334fa9e4066Sahrens */ 1335fa9e4066Sahrens static int 1336478ed9adSEric Taylor get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp) 1337fa9e4066Sahrens { 1338fa9e4066Sahrens char *packed; 1339fa9e4066Sahrens int error; 1340990b4856Slling nvlist_t *list = NULL; 1341fa9e4066Sahrens 1342fa9e4066Sahrens /* 1343e9dbad6fSeschrock * Read in and unpack the user-supplied nvlist. 1344fa9e4066Sahrens */ 1345990b4856Slling if (size == 0) 1346be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1347fa9e4066Sahrens 1348fa9e4066Sahrens packed = kmem_alloc(size, KM_SLEEP); 1349fa9e4066Sahrens 1350478ed9adSEric Taylor if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 1351478ed9adSEric Taylor iflag)) != 0) { 1352fa9e4066Sahrens kmem_free(packed, size); 1353c71c00bbSRichard Yao return (SET_ERROR(EFAULT)); 1354fa9e4066Sahrens } 1355fa9e4066Sahrens 1356990b4856Slling if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { 1357fa9e4066Sahrens kmem_free(packed, size); 1358fa9e4066Sahrens return (error); 1359fa9e4066Sahrens } 1360fa9e4066Sahrens 1361fa9e4066Sahrens kmem_free(packed, size); 1362fa9e4066Sahrens 1363990b4856Slling *nvp = list; 1364fa9e4066Sahrens return (0); 1365fa9e4066Sahrens } 1366fa9e4066Sahrens 13674445fffbSMatthew Ahrens /* 13684445fffbSMatthew Ahrens * Reduce the size of this nvlist until it can be serialized in 'max' bytes. 13694445fffbSMatthew Ahrens * Entries will be removed from the end of the nvlist, and one int32 entry 13704445fffbSMatthew Ahrens * named "N_MORE_ERRORS" will be added indicating how many entries were 13714445fffbSMatthew Ahrens * removed. 13724445fffbSMatthew Ahrens */ 137392241e0bSTom Erickson static int 13744445fffbSMatthew Ahrens nvlist_smush(nvlist_t *errors, size_t max) 137592241e0bSTom Erickson { 137692241e0bSTom Erickson size_t size; 137792241e0bSTom Erickson 13784445fffbSMatthew Ahrens size = fnvlist_size(errors); 137992241e0bSTom Erickson 13804445fffbSMatthew Ahrens if (size > max) { 138192241e0bSTom Erickson nvpair_t *more_errors; 138292241e0bSTom Erickson int n = 0; 138392241e0bSTom Erickson 13844445fffbSMatthew Ahrens if (max < 1024) 1385be6fd75aSMatthew Ahrens return (SET_ERROR(ENOMEM)); 138692241e0bSTom Erickson 13874445fffbSMatthew Ahrens fnvlist_add_int32(errors, ZPROP_N_MORE_ERRORS, 0); 13884445fffbSMatthew Ahrens more_errors = nvlist_prev_nvpair(errors, NULL); 138992241e0bSTom Erickson 139092241e0bSTom Erickson do { 13914445fffbSMatthew Ahrens nvpair_t *pair = nvlist_prev_nvpair(errors, 139292241e0bSTom Erickson more_errors); 13934445fffbSMatthew Ahrens fnvlist_remove_nvpair(errors, pair); 139492241e0bSTom Erickson n++; 13954445fffbSMatthew Ahrens size = fnvlist_size(errors); 13964445fffbSMatthew Ahrens } while (size > max); 139792241e0bSTom Erickson 13984445fffbSMatthew Ahrens fnvlist_remove_nvpair(errors, more_errors); 13994445fffbSMatthew Ahrens fnvlist_add_int32(errors, ZPROP_N_MORE_ERRORS, n); 14004445fffbSMatthew Ahrens ASSERT3U(fnvlist_size(errors), <=, max); 140192241e0bSTom Erickson } 140292241e0bSTom Erickson 140392241e0bSTom Erickson return (0); 140492241e0bSTom Erickson } 140592241e0bSTom Erickson 1406e9dbad6fSeschrock static int 1407e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 1408e9dbad6fSeschrock { 1409e9dbad6fSeschrock char *packed = NULL; 14106e27f868SSam Falkner int error = 0; 1411e9dbad6fSeschrock size_t size; 1412e9dbad6fSeschrock 14134445fffbSMatthew Ahrens size = fnvlist_size(nvl); 1414e9dbad6fSeschrock 1415e9dbad6fSeschrock if (size > zc->zc_nvlist_dst_size) { 1416be6fd75aSMatthew Ahrens error = SET_ERROR(ENOMEM); 1417e9dbad6fSeschrock } else { 14184445fffbSMatthew Ahrens packed = fnvlist_pack(nvl, &size); 14196e27f868SSam Falkner if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 14206e27f868SSam Falkner size, zc->zc_iflags) != 0) 1421be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 14224445fffbSMatthew Ahrens fnvlist_pack_free(packed, size); 1423e9dbad6fSeschrock } 1424e9dbad6fSeschrock 1425e9dbad6fSeschrock zc->zc_nvlist_dst_size = size; 14264445fffbSMatthew Ahrens zc->zc_nvlist_dst_filled = B_TRUE; 1427e9dbad6fSeschrock return (error); 1428e9dbad6fSeschrock } 1429e9dbad6fSeschrock 1430dfc11533SChris Williamson int 1431dfc11533SChris Williamson getzfsvfs_impl(objset_t *os, zfsvfs_t **zfvp) 143214843421SMatthew Ahrens { 1433dfc11533SChris Williamson int error = 0; 1434503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 1435be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1436503ad85cSMatthew Ahrens } 143714843421SMatthew Ahrens 1438503ad85cSMatthew Ahrens mutex_enter(&os->os_user_ptr_lock); 1439af4c679fSSean McEnroe *zfvp = dmu_objset_get_user(os); 1440af4c679fSSean McEnroe if (*zfvp) { 1441af4c679fSSean McEnroe VFS_HOLD((*zfvp)->z_vfs); 144214843421SMatthew Ahrens } else { 1443be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 144414843421SMatthew Ahrens } 1445503ad85cSMatthew Ahrens mutex_exit(&os->os_user_ptr_lock); 1446dfc11533SChris Williamson return (error); 1447dfc11533SChris Williamson } 1448dfc11533SChris Williamson 1449ed992b0aSSerapheim Dimitropoulos int 1450dfc11533SChris Williamson getzfsvfs(const char *dsname, zfsvfs_t **zfvp) 1451dfc11533SChris Williamson { 1452dfc11533SChris Williamson objset_t *os; 1453dfc11533SChris Williamson int error; 1454dfc11533SChris Williamson 1455dfc11533SChris Williamson error = dmu_objset_hold(dsname, FTAG, &os); 1456dfc11533SChris Williamson if (error != 0) 1457dfc11533SChris Williamson return (error); 1458dfc11533SChris Williamson 1459dfc11533SChris Williamson error = getzfsvfs_impl(os, zfvp); 1460503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 146114843421SMatthew Ahrens return (error); 146214843421SMatthew Ahrens } 146314843421SMatthew Ahrens 146414843421SMatthew Ahrens /* 146514843421SMatthew Ahrens * Find a zfsvfs_t for a mounted filesystem, or create our own, in which 146614843421SMatthew Ahrens * case its z_vfs will be NULL, and it will be opened as the owner. 1467ad135b5dSChristopher Siden * If 'writer' is set, the z_teardown_lock will be held for RW_WRITER, 1468ad135b5dSChristopher Siden * which prevents all vnode ops from running. 146914843421SMatthew Ahrens */ 147014843421SMatthew Ahrens static int 14711412a1a2SMark Shellenbaum zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer) 147214843421SMatthew Ahrens { 147314843421SMatthew Ahrens int error = 0; 147414843421SMatthew Ahrens 1475af4c679fSSean McEnroe if (getzfsvfs(name, zfvp) != 0) 1476af4c679fSSean McEnroe error = zfsvfs_create(name, zfvp); 147714843421SMatthew Ahrens if (error == 0) { 1478c9030f6cSAlexander Motin rrm_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER : 14791412a1a2SMark Shellenbaum RW_READER, tag); 1480af4c679fSSean McEnroe if ((*zfvp)->z_unmounted) { 148114843421SMatthew Ahrens /* 148214843421SMatthew Ahrens * XXX we could probably try again, since the unmounting 148314843421SMatthew Ahrens * thread should be just about to disassociate the 148414843421SMatthew Ahrens * objset from the zfsvfs. 148514843421SMatthew Ahrens */ 1486c9030f6cSAlexander Motin rrm_exit(&(*zfvp)->z_teardown_lock, tag); 1487be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 148814843421SMatthew Ahrens } 148914843421SMatthew Ahrens } 149014843421SMatthew Ahrens return (error); 149114843421SMatthew Ahrens } 149214843421SMatthew Ahrens 149314843421SMatthew Ahrens static void 149414843421SMatthew Ahrens zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag) 149514843421SMatthew Ahrens { 1496c9030f6cSAlexander Motin rrm_exit(&zfsvfs->z_teardown_lock, tag); 149714843421SMatthew Ahrens 149814843421SMatthew Ahrens if (zfsvfs->z_vfs) { 149914843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 150014843421SMatthew Ahrens } else { 1501*eb633035STom Caputi dmu_objset_disown(zfsvfs->z_os, B_TRUE, zfsvfs); 150214843421SMatthew Ahrens zfsvfs_free(zfsvfs); 150314843421SMatthew Ahrens } 150414843421SMatthew Ahrens } 150514843421SMatthew Ahrens 1506fa9e4066Sahrens static int 1507fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc) 1508fa9e4066Sahrens { 1509fa9e4066Sahrens int error; 1510990b4856Slling nvlist_t *config, *props = NULL; 15110a48a24eStimh nvlist_t *rootprops = NULL; 15120a48a24eStimh nvlist_t *zplprops = NULL; 151304e56356SAndriy Gapon char *spa_name = zc->zc_name; 1514*eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 1515fa9e4066Sahrens 1516990b4856Slling if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1517478ed9adSEric Taylor zc->zc_iflags, &config)) 1518fa9e4066Sahrens return (error); 15192a6b87f0Sek 1520990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 1521478ed9adSEric Taylor get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1522478ed9adSEric Taylor zc->zc_iflags, &props))) { 1523990b4856Slling nvlist_free(config); 1524990b4856Slling return (error); 1525990b4856Slling } 1526990b4856Slling 15270a48a24eStimh if (props) { 15280a48a24eStimh nvlist_t *nvl = NULL; 1529*eb633035STom Caputi nvlist_t *hidden_args = NULL; 15300a48a24eStimh uint64_t version = SPA_VERSION; 153104e56356SAndriy Gapon char *tname; 15320a48a24eStimh 15330a48a24eStimh (void) nvlist_lookup_uint64(props, 15340a48a24eStimh zpool_prop_to_name(ZPOOL_PROP_VERSION), &version); 1535ad135b5dSChristopher Siden if (!SPA_VERSION_IS_SUPPORTED(version)) { 1536be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 15370a48a24eStimh goto pool_props_bad; 15380a48a24eStimh } 15390a48a24eStimh (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl); 15400a48a24eStimh if (nvl) { 15410a48a24eStimh error = nvlist_dup(nvl, &rootprops, KM_SLEEP); 15420a48a24eStimh if (error != 0) { 15430a48a24eStimh nvlist_free(config); 15440a48a24eStimh nvlist_free(props); 15450a48a24eStimh return (error); 15460a48a24eStimh } 15470a48a24eStimh (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS); 15480a48a24eStimh } 1549*eb633035STom Caputi 1550*eb633035STom Caputi (void) nvlist_lookup_nvlist(props, ZPOOL_HIDDEN_ARGS, 1551*eb633035STom Caputi &hidden_args); 1552*eb633035STom Caputi error = dsl_crypto_params_create_nvlist(DCP_CMD_NONE, 1553*eb633035STom Caputi rootprops, hidden_args, &dcp); 1554*eb633035STom Caputi if (error != 0) { 1555*eb633035STom Caputi nvlist_free(config); 1556*eb633035STom Caputi nvlist_free(props); 1557*eb633035STom Caputi return (error); 1558*eb633035STom Caputi } 1559*eb633035STom Caputi (void) nvlist_remove_all(props, ZPOOL_HIDDEN_ARGS); 1560*eb633035STom Caputi 15610a48a24eStimh VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 15620a48a24eStimh error = zfs_fill_zplprops_root(version, rootprops, 15630a48a24eStimh zplprops, NULL); 15643b2aab18SMatthew Ahrens if (error != 0) 15650a48a24eStimh goto pool_props_bad; 156604e56356SAndriy Gapon 156704e56356SAndriy Gapon if (nvlist_lookup_string(props, 156804e56356SAndriy Gapon zpool_prop_to_name(ZPOOL_PROP_TNAME), &tname) == 0) 156904e56356SAndriy Gapon spa_name = tname; 15700a48a24eStimh } 15710a48a24eStimh 1572*eb633035STom Caputi error = spa_create(zc->zc_name, config, props, zplprops, dcp); 15730a48a24eStimh 15740a48a24eStimh /* 15750a48a24eStimh * Set the remaining root properties 15760a48a24eStimh */ 157704e56356SAndriy Gapon if (!error && (error = zfs_set_prop_nvlist(spa_name, 157892241e0bSTom Erickson ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) 157904e56356SAndriy Gapon (void) spa_destroy(spa_name); 1580fa9e4066Sahrens 15810a48a24eStimh pool_props_bad: 15820a48a24eStimh nvlist_free(rootprops); 15830a48a24eStimh nvlist_free(zplprops); 1584fa9e4066Sahrens nvlist_free(config); 15850a48a24eStimh nvlist_free(props); 1586*eb633035STom Caputi dsl_crypto_params_free(dcp, !!error); 1587990b4856Slling 1588fa9e4066Sahrens return (error); 1589fa9e4066Sahrens } 1590fa9e4066Sahrens 1591fa9e4066Sahrens static int 1592fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc) 1593fa9e4066Sahrens { 1594ecd6cf80Smarks int error; 1595ecd6cf80Smarks zfs_log_history(zc); 1596ecd6cf80Smarks error = spa_destroy(zc->zc_name); 1597681d9761SEric Taylor if (error == 0) 1598681d9761SEric Taylor zvol_remove_minors(zc->zc_name); 1599ecd6cf80Smarks return (error); 1600fa9e4066Sahrens } 1601fa9e4066Sahrens 1602fa9e4066Sahrens static int 1603fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc) 1604fa9e4066Sahrens { 1605990b4856Slling nvlist_t *config, *props = NULL; 1606fa9e4066Sahrens uint64_t guid; 1607468c413aSTim Haley int error; 1608fa9e4066Sahrens 1609990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1610478ed9adSEric Taylor zc->zc_iflags, &config)) != 0) 1611990b4856Slling return (error); 1612990b4856Slling 1613990b4856Slling if (zc->zc_nvlist_src_size != 0 && (error = 1614478ed9adSEric Taylor get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 1615478ed9adSEric Taylor zc->zc_iflags, &props))) { 1616990b4856Slling nvlist_free(config); 1617fa9e4066Sahrens return (error); 1618990b4856Slling } 1619fa9e4066Sahrens 1620fa9e4066Sahrens if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 1621ea8dc4b6Seschrock guid != zc->zc_guid) 1622be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 1623fa9e4066Sahrens else 16244b964adaSGeorge Wilson error = spa_import(zc->zc_name, config, props, zc->zc_cookie); 1625fa9e4066Sahrens 16264b964adaSGeorge Wilson if (zc->zc_nvlist_dst != 0) { 16274b964adaSGeorge Wilson int err; 16284b964adaSGeorge Wilson 16294b964adaSGeorge Wilson if ((err = put_nvlist(zc, config)) != 0) 16304b964adaSGeorge Wilson error = err; 16314b964adaSGeorge Wilson } 1632468c413aSTim Haley 1633fa9e4066Sahrens nvlist_free(config); 1634fa9e4066Sahrens 1635aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 1636990b4856Slling 1637fa9e4066Sahrens return (error); 1638fa9e4066Sahrens } 1639fa9e4066Sahrens 1640fa9e4066Sahrens static int 1641fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc) 1642fa9e4066Sahrens { 1643ecd6cf80Smarks int error; 164489a89ebfSlling boolean_t force = (boolean_t)zc->zc_cookie; 1645394ab0cbSGeorge Wilson boolean_t hardforce = (boolean_t)zc->zc_guid; 164689a89ebfSlling 1647ecd6cf80Smarks zfs_log_history(zc); 1648394ab0cbSGeorge Wilson error = spa_export(zc->zc_name, NULL, force, hardforce); 1649681d9761SEric Taylor if (error == 0) 1650681d9761SEric Taylor zvol_remove_minors(zc->zc_name); 1651ecd6cf80Smarks return (error); 1652fa9e4066Sahrens } 1653fa9e4066Sahrens 1654fa9e4066Sahrens static int 1655fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc) 1656fa9e4066Sahrens { 1657fa9e4066Sahrens nvlist_t *configs; 1658fa9e4066Sahrens int error; 1659fa9e4066Sahrens 1660fa9e4066Sahrens if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 1661be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 1662fa9e4066Sahrens 1663e9dbad6fSeschrock error = put_nvlist(zc, configs); 1664fa9e4066Sahrens 1665fa9e4066Sahrens nvlist_free(configs); 1666fa9e4066Sahrens 1667fa9e4066Sahrens return (error); 1668fa9e4066Sahrens } 1669fa9e4066Sahrens 1670ad135b5dSChristopher Siden /* 1671ad135b5dSChristopher Siden * inputs: 1672ad135b5dSChristopher Siden * zc_name name of the pool 1673ad135b5dSChristopher Siden * 1674ad135b5dSChristopher Siden * outputs: 1675ad135b5dSChristopher Siden * zc_cookie real errno 1676ad135b5dSChristopher Siden * zc_nvlist_dst config nvlist 1677ad135b5dSChristopher Siden * zc_nvlist_dst_size size of config nvlist 1678ad135b5dSChristopher Siden */ 1679fa9e4066Sahrens static int 1680fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc) 1681fa9e4066Sahrens { 1682fa9e4066Sahrens nvlist_t *config; 1683fa9e4066Sahrens int error; 1684ea8dc4b6Seschrock int ret = 0; 1685fa9e4066Sahrens 1686e9dbad6fSeschrock error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 1687e9dbad6fSeschrock sizeof (zc->zc_value)); 1688fa9e4066Sahrens 1689fa9e4066Sahrens if (config != NULL) { 1690e9dbad6fSeschrock ret = put_nvlist(zc, config); 1691fa9e4066Sahrens nvlist_free(config); 1692ea8dc4b6Seschrock 1693ea8dc4b6Seschrock /* 1694ea8dc4b6Seschrock * The config may be present even if 'error' is non-zero. 1695ea8dc4b6Seschrock * In this case we return success, and preserve the real errno 1696ea8dc4b6Seschrock * in 'zc_cookie'. 1697ea8dc4b6Seschrock */ 1698ea8dc4b6Seschrock zc->zc_cookie = error; 1699fa9e4066Sahrens } else { 1700ea8dc4b6Seschrock ret = error; 1701fa9e4066Sahrens } 1702fa9e4066Sahrens 1703ea8dc4b6Seschrock return (ret); 1704fa9e4066Sahrens } 1705fa9e4066Sahrens 1706fa9e4066Sahrens /* 1707fa9e4066Sahrens * Try to import the given pool, returning pool stats as appropriate so that 1708fa9e4066Sahrens * user land knows which devices are available and overall pool health. 1709fa9e4066Sahrens */ 1710fa9e4066Sahrens static int 1711fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc) 1712fa9e4066Sahrens { 1713fa9e4066Sahrens nvlist_t *tryconfig, *config; 1714fa9e4066Sahrens int error; 1715fa9e4066Sahrens 1716990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1717478ed9adSEric Taylor zc->zc_iflags, &tryconfig)) != 0) 1718fa9e4066Sahrens return (error); 1719fa9e4066Sahrens 1720fa9e4066Sahrens config = spa_tryimport(tryconfig); 1721fa9e4066Sahrens 1722fa9e4066Sahrens nvlist_free(tryconfig); 1723fa9e4066Sahrens 1724fa9e4066Sahrens if (config == NULL) 1725be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1726fa9e4066Sahrens 1727e9dbad6fSeschrock error = put_nvlist(zc, config); 1728fa9e4066Sahrens nvlist_free(config); 1729fa9e4066Sahrens 1730fa9e4066Sahrens return (error); 1731fa9e4066Sahrens } 1732fa9e4066Sahrens 17333f9d6ad7SLin Ling /* 17343f9d6ad7SLin Ling * inputs: 17353f9d6ad7SLin Ling * zc_name name of the pool 17363f9d6ad7SLin Ling * zc_cookie scan func (pool_scan_func_t) 17371702cce7SAlek Pinchuk * zc_flags scrub pause/resume flag (pool_scrub_cmd_t) 17383f9d6ad7SLin Ling */ 1739fa9e4066Sahrens static int 17403f9d6ad7SLin Ling zfs_ioc_pool_scan(zfs_cmd_t *zc) 1741fa9e4066Sahrens { 1742fa9e4066Sahrens spa_t *spa; 1743fa9e4066Sahrens int error; 1744fa9e4066Sahrens 174506eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 174606eeb2adSek return (error); 174706eeb2adSek 17481702cce7SAlek Pinchuk if (zc->zc_flags >= POOL_SCRUB_FLAGS_END) 17491702cce7SAlek Pinchuk return (SET_ERROR(EINVAL)); 17501702cce7SAlek Pinchuk 17511702cce7SAlek Pinchuk if (zc->zc_flags == POOL_SCRUB_PAUSE) 17521702cce7SAlek Pinchuk error = spa_scrub_pause_resume(spa, POOL_SCRUB_PAUSE); 17531702cce7SAlek Pinchuk else if (zc->zc_cookie == POOL_SCAN_NONE) 17543f9d6ad7SLin Ling error = spa_scan_stop(spa); 17553f9d6ad7SLin Ling else 17563f9d6ad7SLin Ling error = spa_scan(spa, zc->zc_cookie); 175706eeb2adSek 175806eeb2adSek spa_close(spa, FTAG); 175906eeb2adSek 1760fa9e4066Sahrens return (error); 1761fa9e4066Sahrens } 1762fa9e4066Sahrens 1763fa9e4066Sahrens static int 1764fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc) 1765fa9e4066Sahrens { 1766fa9e4066Sahrens spa_t *spa; 1767fa9e4066Sahrens int error; 1768fa9e4066Sahrens 1769fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1770fa9e4066Sahrens if (error == 0) { 1771fa9e4066Sahrens spa_freeze(spa); 1772fa9e4066Sahrens spa_close(spa, FTAG); 1773fa9e4066Sahrens } 1774fa9e4066Sahrens return (error); 1775fa9e4066Sahrens } 1776fa9e4066Sahrens 1777eaca9bbdSeschrock static int 1778eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc) 1779eaca9bbdSeschrock { 1780eaca9bbdSeschrock spa_t *spa; 1781eaca9bbdSeschrock int error; 1782eaca9bbdSeschrock 178306eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 178406eeb2adSek return (error); 178506eeb2adSek 1786ad135b5dSChristopher Siden if (zc->zc_cookie < spa_version(spa) || 1787ad135b5dSChristopher Siden !SPA_VERSION_IS_SUPPORTED(zc->zc_cookie)) { 1788558d2d50Slling spa_close(spa, FTAG); 1789be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1790558d2d50Slling } 1791558d2d50Slling 1792990b4856Slling spa_upgrade(spa, zc->zc_cookie); 179306eeb2adSek spa_close(spa, FTAG); 179406eeb2adSek 179506eeb2adSek return (error); 179606eeb2adSek } 179706eeb2adSek 179806eeb2adSek static int 179906eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc) 180006eeb2adSek { 180106eeb2adSek spa_t *spa; 180206eeb2adSek char *hist_buf; 180306eeb2adSek uint64_t size; 180406eeb2adSek int error; 180506eeb2adSek 180606eeb2adSek if ((size = zc->zc_history_len) == 0) 1807be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 180806eeb2adSek 180906eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 181006eeb2adSek return (error); 181106eeb2adSek 1812e7437265Sahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 1813d7306b64Sek spa_close(spa, FTAG); 1814be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 1815d7306b64Sek } 1816d7306b64Sek 181706eeb2adSek hist_buf = kmem_alloc(size, KM_SLEEP); 181806eeb2adSek if ((error = spa_history_get(spa, &zc->zc_history_offset, 181906eeb2adSek &zc->zc_history_len, hist_buf)) == 0) { 1820478ed9adSEric Taylor error = ddi_copyout(hist_buf, 1821478ed9adSEric Taylor (void *)(uintptr_t)zc->zc_history, 1822478ed9adSEric Taylor zc->zc_history_len, zc->zc_iflags); 182306eeb2adSek } 182406eeb2adSek 182506eeb2adSek spa_close(spa, FTAG); 182606eeb2adSek kmem_free(hist_buf, size); 182706eeb2adSek return (error); 182806eeb2adSek } 182906eeb2adSek 1830e9103aaeSGarrett D'Amore static int 1831e9103aaeSGarrett D'Amore zfs_ioc_pool_reguid(zfs_cmd_t *zc) 1832e9103aaeSGarrett D'Amore { 1833e9103aaeSGarrett D'Amore spa_t *spa; 1834e9103aaeSGarrett D'Amore int error; 1835e9103aaeSGarrett D'Amore 1836e9103aaeSGarrett D'Amore error = spa_open(zc->zc_name, &spa, FTAG); 1837e9103aaeSGarrett D'Amore if (error == 0) { 1838e9103aaeSGarrett D'Amore error = spa_change_guid(spa); 1839e9103aaeSGarrett D'Amore spa_close(spa, FTAG); 1840e9103aaeSGarrett D'Amore } 1841e9103aaeSGarrett D'Amore return (error); 1842e9103aaeSGarrett D'Amore } 1843e9103aaeSGarrett D'Amore 184455434c77Sek static int 184555434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 184655434c77Sek { 18473b2aab18SMatthew Ahrens return (dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)); 184855434c77Sek } 184955434c77Sek 1850503ad85cSMatthew Ahrens /* 1851503ad85cSMatthew Ahrens * inputs: 1852503ad85cSMatthew Ahrens * zc_name name of filesystem 1853503ad85cSMatthew Ahrens * zc_obj object to find 1854503ad85cSMatthew Ahrens * 1855503ad85cSMatthew Ahrens * outputs: 1856503ad85cSMatthew Ahrens * zc_value name of object 1857503ad85cSMatthew Ahrens */ 185855434c77Sek static int 185955434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc) 186055434c77Sek { 1861503ad85cSMatthew Ahrens objset_t *os; 186255434c77Sek int error; 186355434c77Sek 1864503ad85cSMatthew Ahrens /* XXX reading from objset not owned */ 1865*eb633035STom Caputi if ((error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, 1866*eb633035STom Caputi FTAG, &os)) != 0) 186755434c77Sek return (error); 1868503ad85cSMatthew Ahrens if (dmu_objset_type(os) != DMU_OST_ZFS) { 1869*eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 1870be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1871503ad85cSMatthew Ahrens } 1872503ad85cSMatthew Ahrens error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value, 187355434c77Sek sizeof (zc->zc_value)); 1874*eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 187555434c77Sek 187655434c77Sek return (error); 187755434c77Sek } 187855434c77Sek 187999d5e173STim Haley /* 188099d5e173STim Haley * inputs: 188199d5e173STim Haley * zc_name name of filesystem 188299d5e173STim Haley * zc_obj object to find 188399d5e173STim Haley * 188499d5e173STim Haley * outputs: 188599d5e173STim Haley * zc_stat stats on object 188699d5e173STim Haley * zc_value path to object 188799d5e173STim Haley */ 188899d5e173STim Haley static int 188999d5e173STim Haley zfs_ioc_obj_to_stats(zfs_cmd_t *zc) 189099d5e173STim Haley { 189199d5e173STim Haley objset_t *os; 189299d5e173STim Haley int error; 189399d5e173STim Haley 189499d5e173STim Haley /* XXX reading from objset not owned */ 1895*eb633035STom Caputi if ((error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, 1896*eb633035STom Caputi FTAG, &os)) != 0) 189799d5e173STim Haley return (error); 189899d5e173STim Haley if (dmu_objset_type(os) != DMU_OST_ZFS) { 1899*eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 1900be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 190199d5e173STim Haley } 190299d5e173STim Haley error = zfs_obj_to_stats(os, zc->zc_obj, &zc->zc_stat, zc->zc_value, 190399d5e173STim Haley sizeof (zc->zc_value)); 1904*eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 190599d5e173STim Haley 190699d5e173STim Haley return (error); 190799d5e173STim Haley } 190899d5e173STim Haley 1909fa9e4066Sahrens static int 1910fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc) 1911fa9e4066Sahrens { 1912fa9e4066Sahrens spa_t *spa; 1913fa9e4066Sahrens int error; 1914e7cbe64fSgw nvlist_t *config, **l2cache, **spares; 1915e7cbe64fSgw uint_t nl2cache = 0, nspares = 0; 1916fa9e4066Sahrens 1917fa9e4066Sahrens error = spa_open(zc->zc_name, &spa, FTAG); 1918fa9e4066Sahrens if (error != 0) 1919fa9e4066Sahrens return (error); 1920fa9e4066Sahrens 1921fa94a07fSbrendan error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 1922478ed9adSEric Taylor zc->zc_iflags, &config); 1923fa94a07fSbrendan (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, 1924fa94a07fSbrendan &l2cache, &nl2cache); 1925fa94a07fSbrendan 1926e7cbe64fSgw (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_SPARES, 1927e7cbe64fSgw &spares, &nspares); 1928e7cbe64fSgw 1929b1b8ab34Slling /* 1930b1b8ab34Slling * A root pool with concatenated devices is not supported. 1931e7cbe64fSgw * Thus, can not add a device to a root pool. 1932e7cbe64fSgw * 1933e7cbe64fSgw * Intent log device can not be added to a rootpool because 1934e7cbe64fSgw * during mountroot, zil is replayed, a seperated log device 1935e7cbe64fSgw * can not be accessed during the mountroot time. 1936e7cbe64fSgw * 1937e7cbe64fSgw * l2cache and spare devices are ok to be added to a rootpool. 1938b1b8ab34Slling */ 1939b24ab676SJeff Bonwick if (spa_bootfs(spa) != 0 && nl2cache == 0 && nspares == 0) { 19401195e687SMark J Musante nvlist_free(config); 1941b1b8ab34Slling spa_close(spa, FTAG); 1942be6fd75aSMatthew Ahrens return (SET_ERROR(EDOM)); 1943b1b8ab34Slling } 1944b1b8ab34Slling 1945fa94a07fSbrendan if (error == 0) { 1946fa9e4066Sahrens error = spa_vdev_add(spa, config); 1947fa9e4066Sahrens nvlist_free(config); 1948fa9e4066Sahrens } 1949fa9e4066Sahrens spa_close(spa, FTAG); 1950fa9e4066Sahrens return (error); 1951fa9e4066Sahrens } 1952fa9e4066Sahrens 19533f9d6ad7SLin Ling /* 19543f9d6ad7SLin Ling * inputs: 19553f9d6ad7SLin Ling * zc_name name of the pool 19565cabbc6bSPrashanth Sreenivasa * zc_guid guid of vdev to remove 19575cabbc6bSPrashanth Sreenivasa * zc_cookie cancel removal 19583f9d6ad7SLin Ling */ 1959fa9e4066Sahrens static int 1960fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc) 1961fa9e4066Sahrens { 196299653d4eSeschrock spa_t *spa; 196399653d4eSeschrock int error; 196499653d4eSeschrock 196599653d4eSeschrock error = spa_open(zc->zc_name, &spa, FTAG); 196699653d4eSeschrock if (error != 0) 196799653d4eSeschrock return (error); 19685cabbc6bSPrashanth Sreenivasa if (zc->zc_cookie != 0) { 19695cabbc6bSPrashanth Sreenivasa error = spa_vdev_remove_cancel(spa); 19705cabbc6bSPrashanth Sreenivasa } else { 19715cabbc6bSPrashanth Sreenivasa error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 19725cabbc6bSPrashanth Sreenivasa } 197399653d4eSeschrock spa_close(spa, FTAG); 197499653d4eSeschrock return (error); 1975fa9e4066Sahrens } 1976fa9e4066Sahrens 1977fa9e4066Sahrens static int 19783d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc) 1979fa9e4066Sahrens { 1980fa9e4066Sahrens spa_t *spa; 1981fa9e4066Sahrens int error; 19823d7072f8Seschrock vdev_state_t newstate = VDEV_STATE_UNKNOWN; 1983fa9e4066Sahrens 198406eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1985fa9e4066Sahrens return (error); 19863d7072f8Seschrock switch (zc->zc_cookie) { 19873d7072f8Seschrock case VDEV_STATE_ONLINE: 19883d7072f8Seschrock error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); 19893d7072f8Seschrock break; 1990fa9e4066Sahrens 19913d7072f8Seschrock case VDEV_STATE_OFFLINE: 19923d7072f8Seschrock error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); 19933d7072f8Seschrock break; 1994fa9e4066Sahrens 19953d7072f8Seschrock case VDEV_STATE_FAULTED: 1996069f55e2SEric Schrock if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 1997069f55e2SEric Schrock zc->zc_obj != VDEV_AUX_EXTERNAL) 1998069f55e2SEric Schrock zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 1999069f55e2SEric Schrock 2000069f55e2SEric Schrock error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); 20013d7072f8Seschrock break; 20023d7072f8Seschrock 20033d7072f8Seschrock case VDEV_STATE_DEGRADED: 2004069f55e2SEric Schrock if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && 2005069f55e2SEric Schrock zc->zc_obj != VDEV_AUX_EXTERNAL) 2006069f55e2SEric Schrock zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; 2007069f55e2SEric Schrock 2008069f55e2SEric Schrock error = vdev_degrade(spa, zc->zc_guid, zc->zc_obj); 20093d7072f8Seschrock break; 20103d7072f8Seschrock 20113d7072f8Seschrock default: 2012be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 20133d7072f8Seschrock } 20143d7072f8Seschrock zc->zc_cookie = newstate; 2015fa9e4066Sahrens spa_close(spa, FTAG); 2016fa9e4066Sahrens return (error); 2017fa9e4066Sahrens } 2018fa9e4066Sahrens 2019fa9e4066Sahrens static int 2020fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc) 2021fa9e4066Sahrens { 2022fa9e4066Sahrens spa_t *spa; 2023fa9e4066Sahrens int replacing = zc->zc_cookie; 2024fa9e4066Sahrens nvlist_t *config; 2025fa9e4066Sahrens int error; 2026fa9e4066Sahrens 202706eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2028fa9e4066Sahrens return (error); 2029fa9e4066Sahrens 2030990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 2031478ed9adSEric Taylor zc->zc_iflags, &config)) == 0) { 2032ea8dc4b6Seschrock error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 2033fa9e4066Sahrens nvlist_free(config); 2034fa9e4066Sahrens } 2035fa9e4066Sahrens 2036fa9e4066Sahrens spa_close(spa, FTAG); 2037fa9e4066Sahrens return (error); 2038fa9e4066Sahrens } 2039fa9e4066Sahrens 2040fa9e4066Sahrens static int 2041fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc) 2042fa9e4066Sahrens { 2043fa9e4066Sahrens spa_t *spa; 2044fa9e4066Sahrens int error; 2045fa9e4066Sahrens 204606eeb2adSek if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 2047fa9e4066Sahrens return (error); 2048fa9e4066Sahrens 20498ad4d6ddSJeff Bonwick error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); 2050fa9e4066Sahrens 2051fa9e4066Sahrens spa_close(spa, FTAG); 2052fa9e4066Sahrens return (error); 2053fa9e4066Sahrens } 2054fa9e4066Sahrens 20551195e687SMark J Musante static int 20561195e687SMark J Musante zfs_ioc_vdev_split(zfs_cmd_t *zc) 20571195e687SMark J Musante { 20581195e687SMark J Musante spa_t *spa; 20591195e687SMark J Musante nvlist_t *config, *props = NULL; 20601195e687SMark J Musante int error; 20611195e687SMark J Musante boolean_t exp = !!(zc->zc_cookie & ZPOOL_EXPORT_AFTER_SPLIT); 20621195e687SMark J Musante 20631195e687SMark J Musante if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 20641195e687SMark J Musante return (error); 20651195e687SMark J Musante 20661195e687SMark J Musante if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, 20671195e687SMark J Musante zc->zc_iflags, &config)) { 20681195e687SMark J Musante spa_close(spa, FTAG); 20691195e687SMark J Musante return (error); 20701195e687SMark J Musante } 20711195e687SMark J Musante 20721195e687SMark J Musante if (zc->zc_nvlist_src_size != 0 && (error = 20731195e687SMark J Musante get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 20741195e687SMark J Musante zc->zc_iflags, &props))) { 20751195e687SMark J Musante spa_close(spa, FTAG); 20761195e687SMark J Musante nvlist_free(config); 20771195e687SMark J Musante return (error); 20781195e687SMark J Musante } 20791195e687SMark J Musante 20801195e687SMark J Musante error = spa_vdev_split_mirror(spa, zc->zc_string, config, props, exp); 20811195e687SMark J Musante 20821195e687SMark J Musante spa_close(spa, FTAG); 20831195e687SMark J Musante 20841195e687SMark J Musante nvlist_free(config); 20851195e687SMark J Musante nvlist_free(props); 20861195e687SMark J Musante 20871195e687SMark J Musante return (error); 20881195e687SMark J Musante } 20891195e687SMark J Musante 2090c67d9675Seschrock static int 2091c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc) 2092c67d9675Seschrock { 2093c67d9675Seschrock spa_t *spa; 2094e9dbad6fSeschrock char *path = zc->zc_value; 2095ea8dc4b6Seschrock uint64_t guid = zc->zc_guid; 2096c67d9675Seschrock int error; 2097c67d9675Seschrock 2098c67d9675Seschrock error = spa_open(zc->zc_name, &spa, FTAG); 2099c67d9675Seschrock if (error != 0) 2100c67d9675Seschrock return (error); 2101c67d9675Seschrock 2102c67d9675Seschrock error = spa_vdev_setpath(spa, guid, path); 2103c67d9675Seschrock spa_close(spa, FTAG); 2104c67d9675Seschrock return (error); 2105c67d9675Seschrock } 2106c67d9675Seschrock 21076809eb4eSEric Schrock static int 21086809eb4eSEric Schrock zfs_ioc_vdev_setfru(zfs_cmd_t *zc) 21096809eb4eSEric Schrock { 21106809eb4eSEric Schrock spa_t *spa; 21116809eb4eSEric Schrock char *fru = zc->zc_value; 21126809eb4eSEric Schrock uint64_t guid = zc->zc_guid; 21136809eb4eSEric Schrock int error; 21146809eb4eSEric Schrock 21156809eb4eSEric Schrock error = spa_open(zc->zc_name, &spa, FTAG); 21166809eb4eSEric Schrock if (error != 0) 21176809eb4eSEric Schrock return (error); 21186809eb4eSEric Schrock 21196809eb4eSEric Schrock error = spa_vdev_setfru(spa, guid, fru); 21206809eb4eSEric Schrock spa_close(spa, FTAG); 21216809eb4eSEric Schrock return (error); 21226809eb4eSEric Schrock } 21236809eb4eSEric Schrock 2124fa9e4066Sahrens static int 2125a7f53a56SChris Kirby zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) 2126fa9e4066Sahrens { 2127a7f53a56SChris Kirby int error = 0; 21287f7322feSeschrock nvlist_t *nv; 2129fa9e4066Sahrens 2130a2eea2e1Sahrens dmu_objset_fast_stat(os, &zc->zc_objset_stats); 2131fa9e4066Sahrens 21325ad82045Snd if (zc->zc_nvlist_dst != 0 && 213392241e0bSTom Erickson (error = dsl_prop_get_all(os, &nv)) == 0) { 2134a2eea2e1Sahrens dmu_objset_stats(os, nv); 2135432f72fdSahrens /* 2136bd00f61bSrm * NB: zvol_get_stats() will read the objset contents, 2137432f72fdSahrens * which we aren't supposed to do with a 2138745cd3c5Smaybee * DS_MODE_USER hold, because it could be 2139432f72fdSahrens * inconsistent. So this is a bit of a workaround... 2140503ad85cSMatthew Ahrens * XXX reading with out owning 2141432f72fdSahrens */ 214219b94df9SMatthew Ahrens if (!zc->zc_objset_stats.dds_inconsistent && 214319b94df9SMatthew Ahrens dmu_objset_type(os) == DMU_OST_ZVOL) { 214419b94df9SMatthew Ahrens error = zvol_get_stats(os, nv); 214519b94df9SMatthew Ahrens if (error == EIO) 214619b94df9SMatthew Ahrens return (error); 2147fb09f5aaSMadhav Suresh VERIFY0(error); 2148e7437265Sahrens } 2149e9dbad6fSeschrock error = put_nvlist(zc, nv); 21507f7322feSeschrock nvlist_free(nv); 21517f7322feSeschrock } 2152fa9e4066Sahrens 2153a7f53a56SChris Kirby return (error); 2154a7f53a56SChris Kirby } 2155a7f53a56SChris Kirby 2156a7f53a56SChris Kirby /* 2157a7f53a56SChris Kirby * inputs: 2158a7f53a56SChris Kirby * zc_name name of filesystem 2159a7f53a56SChris Kirby * zc_nvlist_dst_size size of buffer for property nvlist 2160a7f53a56SChris Kirby * 2161a7f53a56SChris Kirby * outputs: 2162a7f53a56SChris Kirby * zc_objset_stats stats 2163a7f53a56SChris Kirby * zc_nvlist_dst property nvlist 2164a7f53a56SChris Kirby * zc_nvlist_dst_size size of property nvlist 2165a7f53a56SChris Kirby */ 2166a7f53a56SChris Kirby static int 2167a7f53a56SChris Kirby zfs_ioc_objset_stats(zfs_cmd_t *zc) 2168a7f53a56SChris Kirby { 21693b2aab18SMatthew Ahrens objset_t *os; 2170a7f53a56SChris Kirby int error; 2171a7f53a56SChris Kirby 21723b2aab18SMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &os); 21733b2aab18SMatthew Ahrens if (error == 0) { 21743b2aab18SMatthew Ahrens error = zfs_ioc_objset_stats_impl(zc, os); 21753b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 21763b2aab18SMatthew Ahrens } 2177a7f53a56SChris Kirby 2178fa9e4066Sahrens return (error); 2179fa9e4066Sahrens } 2180fa9e4066Sahrens 218192241e0bSTom Erickson /* 218292241e0bSTom Erickson * inputs: 218392241e0bSTom Erickson * zc_name name of filesystem 218492241e0bSTom Erickson * zc_nvlist_dst_size size of buffer for property nvlist 218592241e0bSTom Erickson * 218692241e0bSTom Erickson * outputs: 218792241e0bSTom Erickson * zc_nvlist_dst received property nvlist 218892241e0bSTom Erickson * zc_nvlist_dst_size size of received property nvlist 218992241e0bSTom Erickson * 219092241e0bSTom Erickson * Gets received properties (distinct from local properties on or after 219192241e0bSTom Erickson * SPA_VERSION_RECVD_PROPS) for callers who want to differentiate received from 219292241e0bSTom Erickson * local property values. 219392241e0bSTom Erickson */ 219492241e0bSTom Erickson static int 219592241e0bSTom Erickson zfs_ioc_objset_recvd_props(zfs_cmd_t *zc) 219692241e0bSTom Erickson { 21973b2aab18SMatthew Ahrens int error = 0; 219892241e0bSTom Erickson nvlist_t *nv; 219992241e0bSTom Erickson 220092241e0bSTom Erickson /* 220192241e0bSTom Erickson * Without this check, we would return local property values if the 220292241e0bSTom Erickson * caller has not already received properties on or after 220392241e0bSTom Erickson * SPA_VERSION_RECVD_PROPS. 220492241e0bSTom Erickson */ 22053b2aab18SMatthew Ahrens if (!dsl_prop_get_hasrecvd(zc->zc_name)) 2206be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 220792241e0bSTom Erickson 220892241e0bSTom Erickson if (zc->zc_nvlist_dst != 0 && 22093b2aab18SMatthew Ahrens (error = dsl_prop_get_received(zc->zc_name, &nv)) == 0) { 221092241e0bSTom Erickson error = put_nvlist(zc, nv); 221192241e0bSTom Erickson nvlist_free(nv); 221292241e0bSTom Erickson } 221392241e0bSTom Erickson 221492241e0bSTom Erickson return (error); 221592241e0bSTom Erickson } 221692241e0bSTom Erickson 2217de8267e0Stimh static int 2218de8267e0Stimh nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop) 2219de8267e0Stimh { 2220de8267e0Stimh uint64_t value; 2221de8267e0Stimh int error; 2222de8267e0Stimh 2223de8267e0Stimh /* 2224de8267e0Stimh * zfs_get_zplprop() will either find a value or give us 2225de8267e0Stimh * the default value (if there is one). 2226de8267e0Stimh */ 2227de8267e0Stimh if ((error = zfs_get_zplprop(os, prop, &value)) != 0) 2228de8267e0Stimh return (error); 2229de8267e0Stimh VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0); 2230de8267e0Stimh return (0); 2231de8267e0Stimh } 2232de8267e0Stimh 22333cb34c60Sahrens /* 22343cb34c60Sahrens * inputs: 22353cb34c60Sahrens * zc_name name of filesystem 2236de8267e0Stimh * zc_nvlist_dst_size size of buffer for zpl property nvlist 22373cb34c60Sahrens * 22383cb34c60Sahrens * outputs: 2239de8267e0Stimh * zc_nvlist_dst zpl property nvlist 2240de8267e0Stimh * zc_nvlist_dst_size size of zpl property nvlist 22413cb34c60Sahrens */ 2242bd00f61bSrm static int 2243de8267e0Stimh zfs_ioc_objset_zplprops(zfs_cmd_t *zc) 2244bd00f61bSrm { 2245de8267e0Stimh objset_t *os; 2246de8267e0Stimh int err; 2247bd00f61bSrm 2248503ad85cSMatthew Ahrens /* XXX reading without owning */ 2249503ad85cSMatthew Ahrens if (err = dmu_objset_hold(zc->zc_name, FTAG, &os)) 2250de8267e0Stimh return (err); 2251bd00f61bSrm 2252bd00f61bSrm dmu_objset_fast_stat(os, &zc->zc_objset_stats); 2253bd00f61bSrm 2254bd00f61bSrm /* 2255de8267e0Stimh * NB: nvl_add_zplprop() will read the objset contents, 2256745cd3c5Smaybee * which we aren't supposed to do with a DS_MODE_USER 2257745cd3c5Smaybee * hold, because it could be inconsistent. 2258bd00f61bSrm */ 2259dd328bf6SToomas Soome if (zc->zc_nvlist_dst != 0 && 2260de8267e0Stimh !zc->zc_objset_stats.dds_inconsistent && 2261de8267e0Stimh dmu_objset_type(os) == DMU_OST_ZFS) { 2262de8267e0Stimh nvlist_t *nv; 2263de8267e0Stimh 2264de8267e0Stimh VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2265de8267e0Stimh if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && 2266de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && 2267de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && 2268de8267e0Stimh (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) 2269de8267e0Stimh err = put_nvlist(zc, nv); 2270de8267e0Stimh nvlist_free(nv); 2271de8267e0Stimh } else { 2272be6fd75aSMatthew Ahrens err = SET_ERROR(ENOENT); 2273de8267e0Stimh } 2274503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2275de8267e0Stimh return (err); 2276bd00f61bSrm } 2277bd00f61bSrm 227814843421SMatthew Ahrens static boolean_t 227914843421SMatthew Ahrens dataset_name_hidden(const char *name) 228014843421SMatthew Ahrens { 228114843421SMatthew Ahrens /* 228214843421SMatthew Ahrens * Skip over datasets that are not visible in this zone, 228314843421SMatthew Ahrens * internal datasets (which have a $ in their name), and 228414843421SMatthew Ahrens * temporary datasets (which have a % in their name). 228514843421SMatthew Ahrens */ 228614843421SMatthew Ahrens if (strchr(name, '$') != NULL) 228714843421SMatthew Ahrens return (B_TRUE); 228814843421SMatthew Ahrens if (strchr(name, '%') != NULL) 228914843421SMatthew Ahrens return (B_TRUE); 229014843421SMatthew Ahrens if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL)) 229114843421SMatthew Ahrens return (B_TRUE); 229214843421SMatthew Ahrens return (B_FALSE); 229314843421SMatthew Ahrens } 229414843421SMatthew Ahrens 2295de8267e0Stimh /* 2296de8267e0Stimh * inputs: 2297de8267e0Stimh * zc_name name of filesystem 2298de8267e0Stimh * zc_cookie zap cursor 2299de8267e0Stimh * zc_nvlist_dst_size size of buffer for property nvlist 2300de8267e0Stimh * 2301de8267e0Stimh * outputs: 2302de8267e0Stimh * zc_name name of next filesystem 230314843421SMatthew Ahrens * zc_cookie zap cursor 2304de8267e0Stimh * zc_objset_stats stats 2305de8267e0Stimh * zc_nvlist_dst property nvlist 2306de8267e0Stimh * zc_nvlist_dst_size size of property nvlist 2307de8267e0Stimh */ 2308fa9e4066Sahrens static int 2309fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 2310fa9e4066Sahrens { 231187e5029aSahrens objset_t *os; 2312fa9e4066Sahrens int error; 2313fa9e4066Sahrens char *p; 2314620252bcSChris Kirby size_t orig_len = strlen(zc->zc_name); 2315fa9e4066Sahrens 2316620252bcSChris Kirby top: 2317503ad85cSMatthew Ahrens if (error = dmu_objset_hold(zc->zc_name, FTAG, &os)) { 231887e5029aSahrens if (error == ENOENT) 2319be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 232087e5029aSahrens return (error); 2321fa9e4066Sahrens } 2322fa9e4066Sahrens 2323fa9e4066Sahrens p = strrchr(zc->zc_name, '/'); 2324fa9e4066Sahrens if (p == NULL || p[1] != '\0') 2325fa9e4066Sahrens (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 2326fa9e4066Sahrens p = zc->zc_name + strlen(zc->zc_name); 2327fa9e4066Sahrens 2328fa9e4066Sahrens do { 232987e5029aSahrens error = dmu_dir_list_next(os, 233087e5029aSahrens sizeof (zc->zc_name) - (p - zc->zc_name), p, 233187e5029aSahrens NULL, &zc->zc_cookie); 2332fa9e4066Sahrens if (error == ENOENT) 2333be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 233419b94df9SMatthew Ahrens } while (error == 0 && dataset_name_hidden(zc->zc_name)); 2335503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2336fa9e4066Sahrens 2337681d9761SEric Taylor /* 2338681d9761SEric Taylor * If it's an internal dataset (ie. with a '$' in its name), 2339681d9761SEric Taylor * don't try to get stats for it, otherwise we'll return ENOENT. 2340681d9761SEric Taylor */ 2341620252bcSChris Kirby if (error == 0 && strchr(zc->zc_name, '$') == NULL) { 234287e5029aSahrens error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 2343620252bcSChris Kirby if (error == ENOENT) { 2344620252bcSChris Kirby /* We lost a race with destroy, get the next one. */ 2345620252bcSChris Kirby zc->zc_name[orig_len] = '\0'; 2346620252bcSChris Kirby goto top; 2347620252bcSChris Kirby } 2348620252bcSChris Kirby } 2349fa9e4066Sahrens return (error); 2350fa9e4066Sahrens } 2351fa9e4066Sahrens 23523cb34c60Sahrens /* 23533cb34c60Sahrens * inputs: 23543cb34c60Sahrens * zc_name name of filesystem 23553cb34c60Sahrens * zc_cookie zap cursor 23563cb34c60Sahrens * zc_nvlist_dst_size size of buffer for property nvlist 23570d8fa8f8SMartin Matuska * zc_simple when set, only name is requested 23583cb34c60Sahrens * 23593cb34c60Sahrens * outputs: 23603cb34c60Sahrens * zc_name name of next snapshot 23613cb34c60Sahrens * zc_objset_stats stats 23623cb34c60Sahrens * zc_nvlist_dst property nvlist 23633cb34c60Sahrens * zc_nvlist_dst_size size of property nvlist 23643cb34c60Sahrens */ 2365fa9e4066Sahrens static int 2366fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 2367fa9e4066Sahrens { 236887e5029aSahrens objset_t *os; 2369fa9e4066Sahrens int error; 2370fa9e4066Sahrens 2371503ad85cSMatthew Ahrens error = dmu_objset_hold(zc->zc_name, FTAG, &os); 23723b2aab18SMatthew Ahrens if (error != 0) { 2373745cd3c5Smaybee return (error == ENOENT ? ESRCH : error); 23743b2aab18SMatthew Ahrens } 2375fa9e4066Sahrens 2376b81d61a6Slling /* 2377b81d61a6Slling * A dataset name of maximum length cannot have any snapshots, 2378b81d61a6Slling * so exit immediately. 2379b81d61a6Slling */ 23809adfa60dSMatthew Ahrens if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= 23819adfa60dSMatthew Ahrens ZFS_MAX_DATASET_NAME_LEN) { 2382503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 2383be6fd75aSMatthew Ahrens return (SET_ERROR(ESRCH)); 2384fa9e4066Sahrens } 2385fa9e4066Sahrens 238687e5029aSahrens error = dmu_snapshot_list_next(os, 238787e5029aSahrens sizeof (zc->zc_name) - strlen(zc->zc_name), 2388a7f53a56SChris Kirby zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie, 2389a7f53a56SChris Kirby NULL); 2390a7f53a56SChris Kirby 23910d8fa8f8SMartin Matuska if (error == 0 && !zc->zc_simple) { 2392a7f53a56SChris Kirby dsl_dataset_t *ds; 2393a7f53a56SChris Kirby dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool; 2394a7f53a56SChris Kirby 2395a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds); 23963b2aab18SMatthew Ahrens if (error == 0) { 2397a7f53a56SChris Kirby objset_t *ossnap; 2398a7f53a56SChris Kirby 2399a7f53a56SChris Kirby error = dmu_objset_from_ds(ds, &ossnap); 2400a7f53a56SChris Kirby if (error == 0) 2401a7f53a56SChris Kirby error = zfs_ioc_objset_stats_impl(zc, ossnap); 2402a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 2403620252bcSChris Kirby } 2404620252bcSChris Kirby } else if (error == ENOENT) { 2405be6fd75aSMatthew Ahrens error = SET_ERROR(ESRCH); 2406620252bcSChris Kirby } 2407fa9e4066Sahrens 2408a7f53a56SChris Kirby dmu_objset_rele(os, FTAG); 24093cb34c60Sahrens /* if we failed, undo the @ that we tacked on to zc_name */ 24103b2aab18SMatthew Ahrens if (error != 0) 24113cb34c60Sahrens *strchr(zc->zc_name, '@') = '\0'; 2412fa9e4066Sahrens return (error); 2413fa9e4066Sahrens } 2414fa9e4066Sahrens 241592241e0bSTom Erickson static int 241692241e0bSTom Erickson zfs_prop_set_userquota(const char *dsname, nvpair_t *pair) 2417fa9e4066Sahrens { 241892241e0bSTom Erickson const char *propname = nvpair_name(pair); 241992241e0bSTom Erickson uint64_t *valary; 242092241e0bSTom Erickson unsigned int vallen; 242192241e0bSTom Erickson const char *domain; 2422eeb85002STim Haley char *dash; 242392241e0bSTom Erickson zfs_userquota_prop_t type; 242492241e0bSTom Erickson uint64_t rid; 242592241e0bSTom Erickson uint64_t quota; 242692241e0bSTom Erickson zfsvfs_t *zfsvfs; 242792241e0bSTom Erickson int err; 242892241e0bSTom Erickson 242992241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 243092241e0bSTom Erickson nvlist_t *attrs; 243192241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 2432eeb85002STim Haley if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2433eeb85002STim Haley &pair) != 0) 2434be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 243592241e0bSTom Erickson } 2436e9dbad6fSeschrock 2437ecd6cf80Smarks /* 2438eeb85002STim Haley * A correctly constructed propname is encoded as 243992241e0bSTom Erickson * userquota@<rid>-<domain>. 2440ecd6cf80Smarks */ 2441eeb85002STim Haley if ((dash = strchr(propname, '-')) == NULL || 2442eeb85002STim Haley nvpair_value_uint64_array(pair, &valary, &vallen) != 0 || 2443eeb85002STim Haley vallen != 3) 2444be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2445eeb85002STim Haley 2446eeb85002STim Haley domain = dash + 1; 2447eeb85002STim Haley type = valary[0]; 2448eeb85002STim Haley rid = valary[1]; 2449eeb85002STim Haley quota = valary[2]; 2450e9dbad6fSeschrock 24511412a1a2SMark Shellenbaum err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_FALSE); 245292241e0bSTom Erickson if (err == 0) { 245392241e0bSTom Erickson err = zfs_set_userquota(zfsvfs, type, domain, rid, quota); 245492241e0bSTom Erickson zfsvfs_rele(zfsvfs, FTAG); 245592241e0bSTom Erickson } 2456e9dbad6fSeschrock 245792241e0bSTom Erickson return (err); 245892241e0bSTom Erickson } 245914843421SMatthew Ahrens 246092241e0bSTom Erickson /* 246192241e0bSTom Erickson * If the named property is one that has a special function to set its value, 246292241e0bSTom Erickson * return 0 on success and a positive error code on failure; otherwise if it is 246392241e0bSTom Erickson * not one of the special properties handled by this function, return -1. 246492241e0bSTom Erickson * 2465eeb85002STim Haley * XXX: It would be better for callers of the property interface if we handled 246692241e0bSTom Erickson * these special cases in dsl_prop.c (in the dsl layer). 246792241e0bSTom Erickson */ 246892241e0bSTom Erickson static int 246992241e0bSTom Erickson zfs_prop_set_special(const char *dsname, zprop_source_t source, 247092241e0bSTom Erickson nvpair_t *pair) 247192241e0bSTom Erickson { 247292241e0bSTom Erickson const char *propname = nvpair_name(pair); 247392241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 2474*eb633035STom Caputi uint64_t intval = 0; 2475*eb633035STom Caputi char *strval = NULL; 2476b5152584SMatthew Ahrens int err = -1; 2477fa9e4066Sahrens 247892241e0bSTom Erickson if (prop == ZPROP_INVAL) { 247992241e0bSTom Erickson if (zfs_prop_userquota(propname)) 248092241e0bSTom Erickson return (zfs_prop_set_userquota(dsname, pair)); 248192241e0bSTom Erickson return (-1); 248292241e0bSTom Erickson } 248314843421SMatthew Ahrens 248492241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 248592241e0bSTom Erickson nvlist_t *attrs; 248692241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 248792241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 248892241e0bSTom Erickson &pair) == 0); 248992241e0bSTom Erickson } 2490db870a07Sahrens 2491*eb633035STom Caputi /* all special properties are numeric except for keylocation */ 2492*eb633035STom Caputi if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 2493*eb633035STom Caputi strval = fnvpair_value_string(pair); 2494*eb633035STom Caputi } else { 2495*eb633035STom Caputi intval = fnvpair_value_uint64(pair); 2496*eb633035STom Caputi } 249740feaa91Sahrens 249892241e0bSTom Erickson switch (prop) { 249992241e0bSTom Erickson case ZFS_PROP_QUOTA: 250092241e0bSTom Erickson err = dsl_dir_set_quota(dsname, source, intval); 250192241e0bSTom Erickson break; 250292241e0bSTom Erickson case ZFS_PROP_REFQUOTA: 25033b2aab18SMatthew Ahrens err = dsl_dataset_set_refquota(dsname, source, intval); 250492241e0bSTom Erickson break; 2505a2afb611SJerry Jelinek case ZFS_PROP_FILESYSTEM_LIMIT: 2506a2afb611SJerry Jelinek case ZFS_PROP_SNAPSHOT_LIMIT: 2507a2afb611SJerry Jelinek if (intval == UINT64_MAX) { 2508a2afb611SJerry Jelinek /* clearing the limit, just do it */ 2509a2afb611SJerry Jelinek err = 0; 2510a2afb611SJerry Jelinek } else { 2511a2afb611SJerry Jelinek err = dsl_dir_activate_fs_ss_limit(dsname); 2512a2afb611SJerry Jelinek } 2513*eb633035STom Caputi /* 2514*eb633035STom Caputi * Set err to -1 to force the zfs_set_prop_nvlist code down the 2515*eb633035STom Caputi * default path to set the value in the nvlist. 2516*eb633035STom Caputi */ 2517*eb633035STom Caputi if (err == 0) 2518*eb633035STom Caputi err = -1; 2519*eb633035STom Caputi break; 2520*eb633035STom Caputi case ZFS_PROP_KEYLOCATION: 2521*eb633035STom Caputi err = dsl_crypto_can_set_keylocation(dsname, strval); 2522*eb633035STom Caputi 2523a2afb611SJerry Jelinek /* 2524a2afb611SJerry Jelinek * Set err to -1 to force the zfs_set_prop_nvlist code down the 2525a2afb611SJerry Jelinek * default path to set the value in the nvlist. 2526a2afb611SJerry Jelinek */ 2527a2afb611SJerry Jelinek if (err == 0) 2528a2afb611SJerry Jelinek err = -1; 2529a2afb611SJerry Jelinek break; 253092241e0bSTom Erickson case ZFS_PROP_RESERVATION: 253192241e0bSTom Erickson err = dsl_dir_set_reservation(dsname, source, intval); 253292241e0bSTom Erickson break; 253392241e0bSTom Erickson case ZFS_PROP_REFRESERVATION: 25343b2aab18SMatthew Ahrens err = dsl_dataset_set_refreservation(dsname, source, intval); 253592241e0bSTom Erickson break; 253692241e0bSTom Erickson case ZFS_PROP_VOLSIZE: 2537c61ea566SGeorge Wilson err = zvol_set_volsize(dsname, intval); 253892241e0bSTom Erickson break; 253992241e0bSTom Erickson case ZFS_PROP_VERSION: 254092241e0bSTom Erickson { 254192241e0bSTom Erickson zfsvfs_t *zfsvfs; 25429e6eda55Smarks 25431412a1a2SMark Shellenbaum if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) 2544b24ab676SJeff Bonwick break; 2545b24ab676SJeff Bonwick 254692241e0bSTom Erickson err = zfs_set_version(zfsvfs, intval); 254792241e0bSTom Erickson zfsvfs_rele(zfsvfs, FTAG); 2548d0f3f37eSMark Shellenbaum 254992241e0bSTom Erickson if (err == 0 && intval >= ZPL_VERSION_USERSPACE) { 2550b16da2e2SGeorge Wilson zfs_cmd_t *zc; 2551b16da2e2SGeorge Wilson 2552b16da2e2SGeorge Wilson zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 2553b16da2e2SGeorge Wilson (void) strcpy(zc->zc_name, dsname); 2554b16da2e2SGeorge Wilson (void) zfs_ioc_userspace_upgrade(zc); 2555b16da2e2SGeorge Wilson kmem_free(zc, sizeof (zfs_cmd_t)); 255640feaa91Sahrens } 255792241e0bSTom Erickson break; 2558ecd6cf80Smarks } 255992241e0bSTom Erickson default: 256092241e0bSTom Erickson err = -1; 256192241e0bSTom Erickson } 2562e9dbad6fSeschrock 256392241e0bSTom Erickson return (err); 256492241e0bSTom Erickson } 2565a9799022Sck 256692241e0bSTom Erickson /* 256792241e0bSTom Erickson * This function is best effort. If it fails to set any of the given properties, 25684445fffbSMatthew Ahrens * it continues to set as many as it can and returns the last error 25694445fffbSMatthew Ahrens * encountered. If the caller provides a non-NULL errlist, it will be filled in 25704445fffbSMatthew Ahrens * with the list of names of all the properties that failed along with the 25714445fffbSMatthew Ahrens * corresponding error numbers. 257292241e0bSTom Erickson * 25734445fffbSMatthew Ahrens * If every property is set successfully, zero is returned and errlist is not 25744445fffbSMatthew Ahrens * modified. 257592241e0bSTom Erickson */ 257692241e0bSTom Erickson int 257792241e0bSTom Erickson zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, 25784445fffbSMatthew Ahrens nvlist_t *errlist) 257992241e0bSTom Erickson { 258092241e0bSTom Erickson nvpair_t *pair; 258192241e0bSTom Erickson nvpair_t *propval; 258202e383d1STom Erickson int rv = 0; 258392241e0bSTom Erickson uint64_t intval; 258492241e0bSTom Erickson char *strval; 25854445fffbSMatthew Ahrens nvlist_t *genericnvl = fnvlist_alloc(); 25864445fffbSMatthew Ahrens nvlist_t *retrynvl = fnvlist_alloc(); 2587a9799022Sck 258892241e0bSTom Erickson retry: 258992241e0bSTom Erickson pair = NULL; 259092241e0bSTom Erickson while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 259192241e0bSTom Erickson const char *propname = nvpair_name(pair); 259292241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 2593cfa69fd2STom Erickson int err = 0; 2594e9dbad6fSeschrock 259592241e0bSTom Erickson /* decode the property value */ 259692241e0bSTom Erickson propval = pair; 259792241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 259892241e0bSTom Erickson nvlist_t *attrs; 25994445fffbSMatthew Ahrens attrs = fnvpair_value_nvlist(pair); 2600eeb85002STim Haley if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 2601eeb85002STim Haley &propval) != 0) 2602be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 260314843421SMatthew Ahrens } 2604e9dbad6fSeschrock 260592241e0bSTom Erickson /* Validate value type */ 2606eeb85002STim Haley if (err == 0 && prop == ZPROP_INVAL) { 260792241e0bSTom Erickson if (zfs_prop_user(propname)) { 260892241e0bSTom Erickson if (nvpair_type(propval) != DATA_TYPE_STRING) 2609be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 261092241e0bSTom Erickson } else if (zfs_prop_userquota(propname)) { 261192241e0bSTom Erickson if (nvpair_type(propval) != 261292241e0bSTom Erickson DATA_TYPE_UINT64_ARRAY) 2613be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 261419b94df9SMatthew Ahrens } else { 2615be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 26164201a95eSRic Aleshire } 2617eeb85002STim Haley } else if (err == 0) { 261892241e0bSTom Erickson if (nvpair_type(propval) == DATA_TYPE_STRING) { 261992241e0bSTom Erickson if (zfs_prop_get_type(prop) != PROP_TYPE_STRING) 2620be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 262192241e0bSTom Erickson } else if (nvpair_type(propval) == DATA_TYPE_UINT64) { 2622a2eea2e1Sahrens const char *unused; 2623a2eea2e1Sahrens 26244445fffbSMatthew Ahrens intval = fnvpair_value_uint64(propval); 2625e9dbad6fSeschrock 2626e9dbad6fSeschrock switch (zfs_prop_get_type(prop)) { 262791ebeef5Sahrens case PROP_TYPE_NUMBER: 2628e9dbad6fSeschrock break; 262991ebeef5Sahrens case PROP_TYPE_STRING: 2630be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 263192241e0bSTom Erickson break; 263291ebeef5Sahrens case PROP_TYPE_INDEX: 2633acd76fe5Seschrock if (zfs_prop_index_to_string(prop, 263492241e0bSTom Erickson intval, &unused) != 0) 2635be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 2636e9dbad6fSeschrock break; 2637e9dbad6fSeschrock default: 2638e7437265Sahrens cmn_err(CE_PANIC, 2639e7437265Sahrens "unknown property type"); 2640e9dbad6fSeschrock } 2641e9dbad6fSeschrock } else { 2642be6fd75aSMatthew Ahrens err = SET_ERROR(EINVAL); 2643e9dbad6fSeschrock } 2644e9dbad6fSeschrock } 264592241e0bSTom Erickson 264692241e0bSTom Erickson /* Validate permissions */ 264792241e0bSTom Erickson if (err == 0) 264892241e0bSTom Erickson err = zfs_check_settable(dsname, pair, CRED()); 264992241e0bSTom Erickson 265092241e0bSTom Erickson if (err == 0) { 265192241e0bSTom Erickson err = zfs_prop_set_special(dsname, source, pair); 265292241e0bSTom Erickson if (err == -1) { 265392241e0bSTom Erickson /* 265492241e0bSTom Erickson * For better performance we build up a list of 265592241e0bSTom Erickson * properties to set in a single transaction. 265692241e0bSTom Erickson */ 265792241e0bSTom Erickson err = nvlist_add_nvpair(genericnvl, pair); 265892241e0bSTom Erickson } else if (err != 0 && nvl != retrynvl) { 265992241e0bSTom Erickson /* 266092241e0bSTom Erickson * This may be a spurious error caused by 266192241e0bSTom Erickson * receiving quota and reservation out of order. 266292241e0bSTom Erickson * Try again in a second pass. 266392241e0bSTom Erickson */ 266492241e0bSTom Erickson err = nvlist_add_nvpair(retrynvl, pair); 266592241e0bSTom Erickson } 266692241e0bSTom Erickson } 266792241e0bSTom Erickson 26684445fffbSMatthew Ahrens if (err != 0) { 26694445fffbSMatthew Ahrens if (errlist != NULL) 26704445fffbSMatthew Ahrens fnvlist_add_int32(errlist, propname, err); 26714445fffbSMatthew Ahrens rv = err; 26724445fffbSMatthew Ahrens } 2673e9dbad6fSeschrock } 2674e9dbad6fSeschrock 267592241e0bSTom Erickson if (nvl != retrynvl && !nvlist_empty(retrynvl)) { 267692241e0bSTom Erickson nvl = retrynvl; 267792241e0bSTom Erickson goto retry; 267892241e0bSTom Erickson } 267992241e0bSTom Erickson 268092241e0bSTom Erickson if (!nvlist_empty(genericnvl) && 268192241e0bSTom Erickson dsl_props_set(dsname, source, genericnvl) != 0) { 268292241e0bSTom Erickson /* 268392241e0bSTom Erickson * If this fails, we still want to set as many properties as we 268492241e0bSTom Erickson * can, so try setting them individually. 268592241e0bSTom Erickson */ 268692241e0bSTom Erickson pair = NULL; 268792241e0bSTom Erickson while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) { 268892241e0bSTom Erickson const char *propname = nvpair_name(pair); 2689cfa69fd2STom Erickson int err = 0; 269092241e0bSTom Erickson 269192241e0bSTom Erickson propval = pair; 269292241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 269392241e0bSTom Erickson nvlist_t *attrs; 26944445fffbSMatthew Ahrens attrs = fnvpair_value_nvlist(pair); 26954445fffbSMatthew Ahrens propval = fnvlist_lookup_nvpair(attrs, 26964445fffbSMatthew Ahrens ZPROP_VALUE); 269792241e0bSTom Erickson } 269892241e0bSTom Erickson 269992241e0bSTom Erickson if (nvpair_type(propval) == DATA_TYPE_STRING) { 27004445fffbSMatthew Ahrens strval = fnvpair_value_string(propval); 27013b2aab18SMatthew Ahrens err = dsl_prop_set_string(dsname, propname, 27023b2aab18SMatthew Ahrens source, strval); 270392241e0bSTom Erickson } else { 27044445fffbSMatthew Ahrens intval = fnvpair_value_uint64(propval); 27053b2aab18SMatthew Ahrens err = dsl_prop_set_int(dsname, propname, source, 27063b2aab18SMatthew Ahrens intval); 270792241e0bSTom Erickson } 270892241e0bSTom Erickson 270992241e0bSTom Erickson if (err != 0) { 27104445fffbSMatthew Ahrens if (errlist != NULL) { 27114445fffbSMatthew Ahrens fnvlist_add_int32(errlist, propname, 27124445fffbSMatthew Ahrens err); 27134445fffbSMatthew Ahrens } 27144445fffbSMatthew Ahrens rv = err; 271592241e0bSTom Erickson } 271692241e0bSTom Erickson } 27175c0b6a79SRich Morris } 27185c0b6a79SRich Morris nvlist_free(genericnvl); 271992241e0bSTom Erickson nvlist_free(retrynvl); 272092241e0bSTom Erickson 272192241e0bSTom Erickson return (rv); 2722fa9e4066Sahrens } 2723fa9e4066Sahrens 2724ea2f5b9eSMatthew Ahrens /* 2725ea2f5b9eSMatthew Ahrens * Check that all the properties are valid user properties. 2726ea2f5b9eSMatthew Ahrens */ 2727ea2f5b9eSMatthew Ahrens static int 27284445fffbSMatthew Ahrens zfs_check_userprops(const char *fsname, nvlist_t *nvl) 2729ea2f5b9eSMatthew Ahrens { 273092241e0bSTom Erickson nvpair_t *pair = NULL; 2731ea2f5b9eSMatthew Ahrens int error = 0; 2732ea2f5b9eSMatthew Ahrens 273392241e0bSTom Erickson while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { 273492241e0bSTom Erickson const char *propname = nvpair_name(pair); 2735ea2f5b9eSMatthew Ahrens 2736ea2f5b9eSMatthew Ahrens if (!zfs_prop_user(propname) || 273792241e0bSTom Erickson nvpair_type(pair) != DATA_TYPE_STRING) 2738be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2739ea2f5b9eSMatthew Ahrens 2740ea2f5b9eSMatthew Ahrens if (error = zfs_secpolicy_write_perms(fsname, 2741ea2f5b9eSMatthew Ahrens ZFS_DELEG_PERM_USERPROP, CRED())) 2742ea2f5b9eSMatthew Ahrens return (error); 2743ea2f5b9eSMatthew Ahrens 2744ea2f5b9eSMatthew Ahrens if (strlen(propname) >= ZAP_MAXNAMELEN) 2745be6fd75aSMatthew Ahrens return (SET_ERROR(ENAMETOOLONG)); 2746ea2f5b9eSMatthew Ahrens 274778f17100SMatthew Ahrens if (strlen(fnvpair_value_string(pair)) >= ZAP_MAXVALUELEN) 2748ea2f5b9eSMatthew Ahrens return (E2BIG); 2749ea2f5b9eSMatthew Ahrens } 2750ea2f5b9eSMatthew Ahrens return (0); 2751ea2f5b9eSMatthew Ahrens } 2752ea2f5b9eSMatthew Ahrens 275392241e0bSTom Erickson static void 275492241e0bSTom Erickson props_skip(nvlist_t *props, nvlist_t *skipped, nvlist_t **newprops) 275592241e0bSTom Erickson { 275692241e0bSTom Erickson nvpair_t *pair; 275792241e0bSTom Erickson 275892241e0bSTom Erickson VERIFY(nvlist_alloc(newprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 275992241e0bSTom Erickson 276092241e0bSTom Erickson pair = NULL; 276192241e0bSTom Erickson while ((pair = nvlist_next_nvpair(props, pair)) != NULL) { 276292241e0bSTom Erickson if (nvlist_exists(skipped, nvpair_name(pair))) 276392241e0bSTom Erickson continue; 276492241e0bSTom Erickson 276592241e0bSTom Erickson VERIFY(nvlist_add_nvpair(*newprops, pair) == 0); 276692241e0bSTom Erickson } 276792241e0bSTom Erickson } 276892241e0bSTom Erickson 276992241e0bSTom Erickson static int 27703b2aab18SMatthew Ahrens clear_received_props(const char *dsname, nvlist_t *props, 277192241e0bSTom Erickson nvlist_t *skipped) 277292241e0bSTom Erickson { 277392241e0bSTom Erickson int err = 0; 277492241e0bSTom Erickson nvlist_t *cleared_props = NULL; 277592241e0bSTom Erickson props_skip(props, skipped, &cleared_props); 277692241e0bSTom Erickson if (!nvlist_empty(cleared_props)) { 277792241e0bSTom Erickson /* 277892241e0bSTom Erickson * Acts on local properties until the dataset has received 277992241e0bSTom Erickson * properties at least once on or after SPA_VERSION_RECVD_PROPS. 278092241e0bSTom Erickson */ 278192241e0bSTom Erickson zprop_source_t flags = (ZPROP_SRC_NONE | 27823b2aab18SMatthew Ahrens (dsl_prop_get_hasrecvd(dsname) ? ZPROP_SRC_RECEIVED : 0)); 27833b2aab18SMatthew Ahrens err = zfs_set_prop_nvlist(dsname, flags, cleared_props, NULL); 278492241e0bSTom Erickson } 278592241e0bSTom Erickson nvlist_free(cleared_props); 278692241e0bSTom Erickson return (err); 278792241e0bSTom Erickson } 278892241e0bSTom Erickson 27893cb34c60Sahrens /* 27903cb34c60Sahrens * inputs: 27913cb34c60Sahrens * zc_name name of filesystem 27925c0b6a79SRich Morris * zc_value name of property to set 27933cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 279492241e0bSTom Erickson * zc_cookie received properties flag 27953cb34c60Sahrens * 279692241e0bSTom Erickson * outputs: 279792241e0bSTom Erickson * zc_nvlist_dst{_size} error for each unapplied received property 27983cb34c60Sahrens */ 2799fa9e4066Sahrens static int 2800e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc) 2801fa9e4066Sahrens { 2802e9dbad6fSeschrock nvlist_t *nvl; 280392241e0bSTom Erickson boolean_t received = zc->zc_cookie; 280492241e0bSTom Erickson zprop_source_t source = (received ? ZPROP_SRC_RECEIVED : 280592241e0bSTom Erickson ZPROP_SRC_LOCAL); 28064445fffbSMatthew Ahrens nvlist_t *errors; 2807e9dbad6fSeschrock int error; 2808e9dbad6fSeschrock 2809990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 2810478ed9adSEric Taylor zc->zc_iflags, &nvl)) != 0) 2811e9dbad6fSeschrock return (error); 2812e9dbad6fSeschrock 281392241e0bSTom Erickson if (received) { 2814bb0ade09Sahrens nvlist_t *origprops; 2815bb0ade09Sahrens 28163b2aab18SMatthew Ahrens if (dsl_prop_get_received(zc->zc_name, &origprops) == 0) { 28173b2aab18SMatthew Ahrens (void) clear_received_props(zc->zc_name, 28183b2aab18SMatthew Ahrens origprops, nvl); 28193b2aab18SMatthew Ahrens nvlist_free(origprops); 2820bb0ade09Sahrens } 28213b2aab18SMatthew Ahrens 28223b2aab18SMatthew Ahrens error = dsl_prop_set_hasrecvd(zc->zc_name); 2823bb0ade09Sahrens } 2824bb0ade09Sahrens 28254445fffbSMatthew Ahrens errors = fnvlist_alloc(); 28263b2aab18SMatthew Ahrens if (error == 0) 28273b2aab18SMatthew Ahrens error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, errors); 282892241e0bSTom Erickson 2829dd328bf6SToomas Soome if (zc->zc_nvlist_dst != 0 && errors != NULL) { 283092241e0bSTom Erickson (void) put_nvlist(zc, errors); 283192241e0bSTom Erickson } 2832ecd6cf80Smarks 283392241e0bSTom Erickson nvlist_free(errors); 2834e9dbad6fSeschrock nvlist_free(nvl); 2835e9dbad6fSeschrock return (error); 2836fa9e4066Sahrens } 2837fa9e4066Sahrens 28383cb34c60Sahrens /* 28393cb34c60Sahrens * inputs: 28403cb34c60Sahrens * zc_name name of filesystem 28413cb34c60Sahrens * zc_value name of property to inherit 284292241e0bSTom Erickson * zc_cookie revert to received value if TRUE 28433cb34c60Sahrens * 28443cb34c60Sahrens * outputs: none 28453cb34c60Sahrens */ 2846e45ce728Sahrens static int 2847e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc) 2848e45ce728Sahrens { 284992241e0bSTom Erickson const char *propname = zc->zc_value; 285092241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 285192241e0bSTom Erickson boolean_t received = zc->zc_cookie; 285292241e0bSTom Erickson zprop_source_t source = (received 285392241e0bSTom Erickson ? ZPROP_SRC_NONE /* revert to received value, if any */ 285492241e0bSTom Erickson : ZPROP_SRC_INHERITED); /* explicitly inherit */ 285592241e0bSTom Erickson 285692241e0bSTom Erickson if (received) { 285792241e0bSTom Erickson nvlist_t *dummy; 285892241e0bSTom Erickson nvpair_t *pair; 285992241e0bSTom Erickson zprop_type_t type; 286092241e0bSTom Erickson int err; 286192241e0bSTom Erickson 286292241e0bSTom Erickson /* 286392241e0bSTom Erickson * zfs_prop_set_special() expects properties in the form of an 286492241e0bSTom Erickson * nvpair with type info. 286592241e0bSTom Erickson */ 286692241e0bSTom Erickson if (prop == ZPROP_INVAL) { 286792241e0bSTom Erickson if (!zfs_prop_user(propname)) 2868be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 286992241e0bSTom Erickson 287092241e0bSTom Erickson type = PROP_TYPE_STRING; 2871a79992aaSTom Erickson } else if (prop == ZFS_PROP_VOLSIZE || 2872a79992aaSTom Erickson prop == ZFS_PROP_VERSION) { 2873be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 287492241e0bSTom Erickson } else { 287592241e0bSTom Erickson type = zfs_prop_get_type(prop); 287692241e0bSTom Erickson } 287792241e0bSTom Erickson 287892241e0bSTom Erickson VERIFY(nvlist_alloc(&dummy, NV_UNIQUE_NAME, KM_SLEEP) == 0); 287992241e0bSTom Erickson 288092241e0bSTom Erickson switch (type) { 288192241e0bSTom Erickson case PROP_TYPE_STRING: 288292241e0bSTom Erickson VERIFY(0 == nvlist_add_string(dummy, propname, "")); 288392241e0bSTom Erickson break; 288492241e0bSTom Erickson case PROP_TYPE_NUMBER: 288592241e0bSTom Erickson case PROP_TYPE_INDEX: 288692241e0bSTom Erickson VERIFY(0 == nvlist_add_uint64(dummy, propname, 0)); 288792241e0bSTom Erickson break; 288892241e0bSTom Erickson default: 288992241e0bSTom Erickson nvlist_free(dummy); 2890be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 289192241e0bSTom Erickson } 289292241e0bSTom Erickson 289392241e0bSTom Erickson pair = nvlist_next_nvpair(dummy, NULL); 289492241e0bSTom Erickson err = zfs_prop_set_special(zc->zc_name, source, pair); 289592241e0bSTom Erickson nvlist_free(dummy); 289692241e0bSTom Erickson if (err != -1) 289792241e0bSTom Erickson return (err); /* special property already handled */ 289892241e0bSTom Erickson } else { 289992241e0bSTom Erickson /* 290092241e0bSTom Erickson * Only check this in the non-received case. We want to allow 290192241e0bSTom Erickson * 'inherit -S' to revert non-inheritable properties like quota 290292241e0bSTom Erickson * and reservation to the received or default values even though 290392241e0bSTom Erickson * they are not considered inheritable. 290492241e0bSTom Erickson */ 290592241e0bSTom Erickson if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop)) 2906be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 290792241e0bSTom Erickson } 290892241e0bSTom Erickson 29094445fffbSMatthew Ahrens /* property name has been validated by zfs_secpolicy_inherit_prop() */ 29103b2aab18SMatthew Ahrens return (dsl_prop_inherit(zc->zc_name, zc->zc_value, source)); 2911e45ce728Sahrens } 2912e45ce728Sahrens 2913b1b8ab34Slling static int 291411a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc) 2915b1b8ab34Slling { 2916990b4856Slling nvlist_t *props; 2917b1b8ab34Slling spa_t *spa; 2918990b4856Slling int error; 291992241e0bSTom Erickson nvpair_t *pair; 2920b1b8ab34Slling 292192241e0bSTom Erickson if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 292292241e0bSTom Erickson zc->zc_iflags, &props)) 2923b1b8ab34Slling return (error); 2924b1b8ab34Slling 2925379c004dSEric Schrock /* 2926379c004dSEric Schrock * If the only property is the configfile, then just do a spa_lookup() 2927379c004dSEric Schrock * to handle the faulted case. 2928379c004dSEric Schrock */ 292992241e0bSTom Erickson pair = nvlist_next_nvpair(props, NULL); 293092241e0bSTom Erickson if (pair != NULL && strcmp(nvpair_name(pair), 2931379c004dSEric Schrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && 293292241e0bSTom Erickson nvlist_next_nvpair(props, pair) == NULL) { 2933379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 2934379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) { 2935379c004dSEric Schrock spa_configfile_set(spa, props, B_FALSE); 29365cabbc6bSPrashanth Sreenivasa spa_write_cachefile(spa, B_FALSE, B_TRUE); 2937379c004dSEric Schrock } 2938379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 2939b693757aSEric Schrock if (spa != NULL) { 2940b693757aSEric Schrock nvlist_free(props); 2941379c004dSEric Schrock return (0); 2942b693757aSEric Schrock } 2943379c004dSEric Schrock } 2944379c004dSEric Schrock 2945b1b8ab34Slling if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2946990b4856Slling nvlist_free(props); 2947b1b8ab34Slling return (error); 2948b1b8ab34Slling } 2949b1b8ab34Slling 2950990b4856Slling error = spa_prop_set(spa, props); 2951b1b8ab34Slling 2952990b4856Slling nvlist_free(props); 2953b1b8ab34Slling spa_close(spa, FTAG); 2954b1b8ab34Slling 2955b1b8ab34Slling return (error); 2956b1b8ab34Slling } 2957b1b8ab34Slling 2958b1b8ab34Slling static int 295911a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc) 2960b1b8ab34Slling { 2961b1b8ab34Slling spa_t *spa; 2962b1b8ab34Slling int error; 2963b1b8ab34Slling nvlist_t *nvp = NULL; 2964b1b8ab34Slling 2965379c004dSEric Schrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 2966379c004dSEric Schrock /* 2967379c004dSEric Schrock * If the pool is faulted, there may be properties we can still 2968379c004dSEric Schrock * get (such as altroot and cachefile), so attempt to get them 2969379c004dSEric Schrock * anyway. 2970379c004dSEric Schrock */ 2971379c004dSEric Schrock mutex_enter(&spa_namespace_lock); 2972379c004dSEric Schrock if ((spa = spa_lookup(zc->zc_name)) != NULL) 2973379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 2974379c004dSEric Schrock mutex_exit(&spa_namespace_lock); 2975379c004dSEric Schrock } else { 2976379c004dSEric Schrock error = spa_prop_get(spa, &nvp); 2977379c004dSEric Schrock spa_close(spa, FTAG); 2978379c004dSEric Schrock } 2979b1b8ab34Slling 2980dd328bf6SToomas Soome if (error == 0 && zc->zc_nvlist_dst != 0) 2981b1b8ab34Slling error = put_nvlist(zc, nvp); 2982b1b8ab34Slling else 2983be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 2984b1b8ab34Slling 2985379c004dSEric Schrock nvlist_free(nvp); 2986b1b8ab34Slling return (error); 2987b1b8ab34Slling } 2988b1b8ab34Slling 29893cb34c60Sahrens /* 29903cb34c60Sahrens * inputs: 29913cb34c60Sahrens * zc_name name of filesystem 29923cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 29933cb34c60Sahrens * zc_perm_action allow/unallow flag 29943cb34c60Sahrens * 29953cb34c60Sahrens * outputs: none 29963cb34c60Sahrens */ 2997ecd6cf80Smarks static int 2998ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc) 2999ecd6cf80Smarks { 3000ecd6cf80Smarks int error; 3001ecd6cf80Smarks nvlist_t *fsaclnv = NULL; 3002ecd6cf80Smarks 3003990b4856Slling if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 3004478ed9adSEric Taylor zc->zc_iflags, &fsaclnv)) != 0) 3005ecd6cf80Smarks return (error); 3006ecd6cf80Smarks 3007ecd6cf80Smarks /* 3008ecd6cf80Smarks * Verify nvlist is constructed correctly 3009ecd6cf80Smarks */ 3010ecd6cf80Smarks if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { 3011ecd6cf80Smarks nvlist_free(fsaclnv); 3012be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3013ecd6cf80Smarks } 3014ecd6cf80Smarks 3015ecd6cf80Smarks /* 3016ecd6cf80Smarks * If we don't have PRIV_SYS_MOUNT, then validate 3017ecd6cf80Smarks * that user is allowed to hand out each permission in 3018ecd6cf80Smarks * the nvlist(s) 3019ecd6cf80Smarks */ 3020ecd6cf80Smarks 302191ebeef5Sahrens error = secpolicy_zfs(CRED()); 30223b2aab18SMatthew Ahrens if (error != 0) { 302391ebeef5Sahrens if (zc->zc_perm_action == B_FALSE) { 302491ebeef5Sahrens error = dsl_deleg_can_allow(zc->zc_name, 302591ebeef5Sahrens fsaclnv, CRED()); 302691ebeef5Sahrens } else { 302791ebeef5Sahrens error = dsl_deleg_can_unallow(zc->zc_name, 302891ebeef5Sahrens fsaclnv, CRED()); 302991ebeef5Sahrens } 3030ecd6cf80Smarks } 3031ecd6cf80Smarks 3032ecd6cf80Smarks if (error == 0) 3033ecd6cf80Smarks error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); 3034ecd6cf80Smarks 3035ecd6cf80Smarks nvlist_free(fsaclnv); 3036ecd6cf80Smarks return (error); 3037ecd6cf80Smarks } 3038ecd6cf80Smarks 30393cb34c60Sahrens /* 30403cb34c60Sahrens * inputs: 30413cb34c60Sahrens * zc_name name of filesystem 30423cb34c60Sahrens * 30433cb34c60Sahrens * outputs: 30443cb34c60Sahrens * zc_nvlist_src{_size} nvlist of delegated permissions 30453cb34c60Sahrens */ 3046ecd6cf80Smarks static int 3047ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc) 3048ecd6cf80Smarks { 3049ecd6cf80Smarks nvlist_t *nvp; 3050ecd6cf80Smarks int error; 3051ecd6cf80Smarks 3052ecd6cf80Smarks if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { 3053ecd6cf80Smarks error = put_nvlist(zc, nvp); 3054ecd6cf80Smarks nvlist_free(nvp); 3055ecd6cf80Smarks } 3056ecd6cf80Smarks 3057ecd6cf80Smarks return (error); 3058ecd6cf80Smarks } 3059ecd6cf80Smarks 3060ecd6cf80Smarks /* ARGSUSED */ 3061fa9e4066Sahrens static void 3062ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 3063fa9e4066Sahrens { 3064da6c28aaSamw zfs_creat_t *zct = arg; 3065da6c28aaSamw 3066de8267e0Stimh zfs_create_fs(os, cr, zct->zct_zplprops, tx); 3067da6c28aaSamw } 3068da6c28aaSamw 3069de8267e0Stimh #define ZFS_PROP_UNDEFINED ((uint64_t)-1) 3070da6c28aaSamw 3071da6c28aaSamw /* 3072de8267e0Stimh * inputs: 30730a48a24eStimh * os parent objset pointer (NULL if root fs) 3074f7170741SWill Andrews * fuids_ok fuids allowed in this version of the spa? 3075f7170741SWill Andrews * sa_ok SAs allowed in this version of the spa? 3076f7170741SWill Andrews * createprops list of properties requested by creator 3077de8267e0Stimh * 3078de8267e0Stimh * outputs: 3079de8267e0Stimh * zplprops values for the zplprops we attach to the master node object 30800a48a24eStimh * is_ci true if requested file system will be purely case-insensitive 3081da6c28aaSamw * 3082de8267e0Stimh * Determine the settings for utf8only, normalization and 3083de8267e0Stimh * casesensitivity. Specific values may have been requested by the 3084de8267e0Stimh * creator and/or we can inherit values from the parent dataset. If 3085de8267e0Stimh * the file system is of too early a vintage, a creator can not 3086de8267e0Stimh * request settings for these properties, even if the requested 3087de8267e0Stimh * setting is the default value. We don't actually want to create dsl 3088de8267e0Stimh * properties for these, so remove them from the source nvlist after 3089de8267e0Stimh * processing. 3090da6c28aaSamw */ 3091da6c28aaSamw static int 309214843421SMatthew Ahrens zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, 30930a586ceaSMark Shellenbaum boolean_t fuids_ok, boolean_t sa_ok, nvlist_t *createprops, 30940a586ceaSMark Shellenbaum nvlist_t *zplprops, boolean_t *is_ci) 3095da6c28aaSamw { 3096de8267e0Stimh uint64_t sense = ZFS_PROP_UNDEFINED; 3097de8267e0Stimh uint64_t norm = ZFS_PROP_UNDEFINED; 3098de8267e0Stimh uint64_t u8 = ZFS_PROP_UNDEFINED; 3099da6c28aaSamw 3100de8267e0Stimh ASSERT(zplprops != NULL); 3101da6c28aaSamw 3102b127fe3cSAndriy Gapon if (os != NULL && os->os_phys->os_type != DMU_OST_ZFS) 3103b127fe3cSAndriy Gapon return (SET_ERROR(EINVAL)); 3104b127fe3cSAndriy Gapon 3105de8267e0Stimh /* 3106de8267e0Stimh * Pull out creator prop choices, if any. 3107de8267e0Stimh */ 3108de8267e0Stimh if (createprops) { 31090a48a24eStimh (void) nvlist_lookup_uint64(createprops, 31100a48a24eStimh zfs_prop_to_name(ZFS_PROP_VERSION), &zplver); 3111de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 3112de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm); 3113de8267e0Stimh (void) nvlist_remove_all(createprops, 3114de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE)); 3115de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 3116de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8); 3117de8267e0Stimh (void) nvlist_remove_all(createprops, 3118de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 3119de8267e0Stimh (void) nvlist_lookup_uint64(createprops, 3120de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), &sense); 3121de8267e0Stimh (void) nvlist_remove_all(createprops, 3122de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE)); 3123de8267e0Stimh } 3124da6c28aaSamw 3125c2a93d44Stimh /* 31260a48a24eStimh * If the zpl version requested is whacky or the file system 31270a48a24eStimh * or pool is version is too "young" to support normalization 31280a48a24eStimh * and the creator tried to set a value for one of the props, 31290a48a24eStimh * error out. 3130c2a93d44Stimh */ 31310a48a24eStimh if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) || 31320a48a24eStimh (zplver >= ZPL_VERSION_FUID && !fuids_ok) || 31330a586ceaSMark Shellenbaum (zplver >= ZPL_VERSION_SA && !sa_ok) || 31340a48a24eStimh (zplver < ZPL_VERSION_NORMALIZATION && 3135de8267e0Stimh (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED || 31360a48a24eStimh sense != ZFS_PROP_UNDEFINED))) 3137be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 3138c2a93d44Stimh 3139de8267e0Stimh /* 3140de8267e0Stimh * Put the version in the zplprops 3141de8267e0Stimh */ 3142de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3143de8267e0Stimh zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0); 3144da6c28aaSamw 3145de8267e0Stimh if (norm == ZFS_PROP_UNDEFINED) 3146de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); 3147de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3148de8267e0Stimh zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); 3149da6c28aaSamw 3150c2a93d44Stimh /* 3151de8267e0Stimh * If we're normalizing, names must always be valid UTF-8 strings. 3152c2a93d44Stimh */ 3153de8267e0Stimh if (norm) 3154de8267e0Stimh u8 = 1; 3155de8267e0Stimh if (u8 == ZFS_PROP_UNDEFINED) 3156de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8) == 0); 3157de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3158de8267e0Stimh zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0); 3159de8267e0Stimh 3160de8267e0Stimh if (sense == ZFS_PROP_UNDEFINED) 3161de8267e0Stimh VERIFY(zfs_get_zplprop(os, ZFS_PROP_CASE, &sense) == 0); 3162de8267e0Stimh VERIFY(nvlist_add_uint64(zplprops, 3163de8267e0Stimh zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); 3164c2a93d44Stimh 3165ab04eb8eStimh if (is_ci) 3166ab04eb8eStimh *is_ci = (sense == ZFS_CASE_INSENSITIVE); 3167ab04eb8eStimh 3168da6c28aaSamw return (0); 3169fa9e4066Sahrens } 3170fa9e4066Sahrens 31710a48a24eStimh static int 31720a48a24eStimh zfs_fill_zplprops(const char *dataset, nvlist_t *createprops, 31730a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 31740a48a24eStimh { 31750a586ceaSMark Shellenbaum boolean_t fuids_ok, sa_ok; 31760a48a24eStimh uint64_t zplver = ZPL_VERSION; 31770a48a24eStimh objset_t *os = NULL; 31789adfa60dSMatthew Ahrens char parentname[ZFS_MAX_DATASET_NAME_LEN]; 31790a48a24eStimh char *cp; 31800a586ceaSMark Shellenbaum spa_t *spa; 31810a586ceaSMark Shellenbaum uint64_t spa_vers; 31820a48a24eStimh int error; 31830a48a24eStimh 31840a48a24eStimh (void) strlcpy(parentname, dataset, sizeof (parentname)); 31850a48a24eStimh cp = strrchr(parentname, '/'); 31860a48a24eStimh ASSERT(cp != NULL); 31870a48a24eStimh cp[0] = '\0'; 31880a48a24eStimh 31890a586ceaSMark Shellenbaum if ((error = spa_open(dataset, &spa, FTAG)) != 0) 31900a586ceaSMark Shellenbaum return (error); 31910a586ceaSMark Shellenbaum 31920a586ceaSMark Shellenbaum spa_vers = spa_version(spa); 31930a586ceaSMark Shellenbaum spa_close(spa, FTAG); 31940a586ceaSMark Shellenbaum 31950a586ceaSMark Shellenbaum zplver = zfs_zpl_version_map(spa_vers); 31960a586ceaSMark Shellenbaum fuids_ok = (zplver >= ZPL_VERSION_FUID); 31970a586ceaSMark Shellenbaum sa_ok = (zplver >= ZPL_VERSION_SA); 31980a48a24eStimh 31990a48a24eStimh /* 32000a48a24eStimh * Open parent object set so we can inherit zplprop values. 32010a48a24eStimh */ 3202503ad85cSMatthew Ahrens if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0) 32030a48a24eStimh return (error); 32040a48a24eStimh 32050a586ceaSMark Shellenbaum error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, sa_ok, createprops, 32060a48a24eStimh zplprops, is_ci); 3207503ad85cSMatthew Ahrens dmu_objset_rele(os, FTAG); 32080a48a24eStimh return (error); 32090a48a24eStimh } 32100a48a24eStimh 32110a48a24eStimh static int 32120a48a24eStimh zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops, 32130a48a24eStimh nvlist_t *zplprops, boolean_t *is_ci) 32140a48a24eStimh { 32150a586ceaSMark Shellenbaum boolean_t fuids_ok; 32160a586ceaSMark Shellenbaum boolean_t sa_ok; 32170a48a24eStimh uint64_t zplver = ZPL_VERSION; 32180a48a24eStimh int error; 32190a48a24eStimh 32200a586ceaSMark Shellenbaum zplver = zfs_zpl_version_map(spa_vers); 32210a586ceaSMark Shellenbaum fuids_ok = (zplver >= ZPL_VERSION_FUID); 32220a586ceaSMark Shellenbaum sa_ok = (zplver >= ZPL_VERSION_SA); 32230a48a24eStimh 32240a586ceaSMark Shellenbaum error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, sa_ok, 32250a586ceaSMark Shellenbaum createprops, zplprops, is_ci); 32260a48a24eStimh return (error); 32270a48a24eStimh } 32280a48a24eStimh 32293cb34c60Sahrens /* 32304445fffbSMatthew Ahrens * innvl: { 32314445fffbSMatthew Ahrens * "type" -> dmu_objset_type_t (int32) 32324445fffbSMatthew Ahrens * (optional) "props" -> { prop -> value } 3233*eb633035STom Caputi * (optional) "hidden_args" -> { "wkeydata" -> value } 3234*eb633035STom Caputi * raw uint8_t array of encryption wrapping key data (32 bytes) 32354445fffbSMatthew Ahrens * } 32363cb34c60Sahrens * 32374445fffbSMatthew Ahrens * outnvl: propname -> error code (int32) 32383cb34c60Sahrens */ 3239fa9e4066Sahrens static int 32404445fffbSMatthew Ahrens zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 3241fa9e4066Sahrens { 3242fa9e4066Sahrens int error = 0; 32434445fffbSMatthew Ahrens zfs_creat_t zct = { 0 }; 3244ecd6cf80Smarks nvlist_t *nvprops = NULL; 3245*eb633035STom Caputi nvlist_t *hidden_args = NULL; 3246ecd6cf80Smarks void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); 32474445fffbSMatthew Ahrens int32_t type32; 32484445fffbSMatthew Ahrens dmu_objset_type_t type; 32494445fffbSMatthew Ahrens boolean_t is_insensitive = B_FALSE; 3250*eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 3251fa9e4066Sahrens 32524445fffbSMatthew Ahrens if (nvlist_lookup_int32(innvl, "type", &type32) != 0) 3253be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 32544445fffbSMatthew Ahrens type = type32; 32554445fffbSMatthew Ahrens (void) nvlist_lookup_nvlist(innvl, "props", &nvprops); 3256*eb633035STom Caputi (void) nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args); 3257fa9e4066Sahrens 32584445fffbSMatthew Ahrens switch (type) { 3259fa9e4066Sahrens case DMU_OST_ZFS: 3260fa9e4066Sahrens cbfunc = zfs_create_cb; 3261fa9e4066Sahrens break; 3262fa9e4066Sahrens 3263fa9e4066Sahrens case DMU_OST_ZVOL: 3264fa9e4066Sahrens cbfunc = zvol_create_cb; 3265fa9e4066Sahrens break; 3266fa9e4066Sahrens 3267fa9e4066Sahrens default: 32681d452cf5Sahrens cbfunc = NULL; 3269e7cbe64fSgw break; 3270fa9e4066Sahrens } 32714445fffbSMatthew Ahrens if (strchr(fsname, '@') || 32724445fffbSMatthew Ahrens strchr(fsname, '%')) 3273be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3274fa9e4066Sahrens 3275da6c28aaSamw zct.zct_props = nvprops; 3276da6c28aaSamw 32774445fffbSMatthew Ahrens if (cbfunc == NULL) 3278be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 32794445fffbSMatthew Ahrens 32804445fffbSMatthew Ahrens if (type == DMU_OST_ZVOL) { 32814445fffbSMatthew Ahrens uint64_t volsize, volblocksize; 32824445fffbSMatthew Ahrens 32834445fffbSMatthew Ahrens if (nvprops == NULL) 3284be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 32854445fffbSMatthew Ahrens if (nvlist_lookup_uint64(nvprops, 32864445fffbSMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) != 0) 3287be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3288fa9e4066Sahrens 32894445fffbSMatthew Ahrens if ((error = nvlist_lookup_uint64(nvprops, 32904445fffbSMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 32914445fffbSMatthew Ahrens &volblocksize)) != 0 && error != ENOENT) 3292be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 32934445fffbSMatthew Ahrens 32944445fffbSMatthew Ahrens if (error != 0) 32954445fffbSMatthew Ahrens volblocksize = zfs_prop_default_numeric( 32964445fffbSMatthew Ahrens ZFS_PROP_VOLBLOCKSIZE); 32974445fffbSMatthew Ahrens 32984445fffbSMatthew Ahrens if ((error = zvol_check_volblocksize( 32994445fffbSMatthew Ahrens volblocksize)) != 0 || 33004445fffbSMatthew Ahrens (error = zvol_check_volsize(volsize, 33014445fffbSMatthew Ahrens volblocksize)) != 0) 3302fa9e4066Sahrens return (error); 33034445fffbSMatthew Ahrens } else if (type == DMU_OST_ZFS) { 33044445fffbSMatthew Ahrens int error; 3305ab04eb8eStimh 33064445fffbSMatthew Ahrens /* 33074445fffbSMatthew Ahrens * We have to have normalization and 33084445fffbSMatthew Ahrens * case-folding flags correct when we do the 33094445fffbSMatthew Ahrens * file system creation, so go figure them out 33104445fffbSMatthew Ahrens * now. 33114445fffbSMatthew Ahrens */ 33124445fffbSMatthew Ahrens VERIFY(nvlist_alloc(&zct.zct_zplprops, 33134445fffbSMatthew Ahrens NV_UNIQUE_NAME, KM_SLEEP) == 0); 33144445fffbSMatthew Ahrens error = zfs_fill_zplprops(fsname, nvprops, 33154445fffbSMatthew Ahrens zct.zct_zplprops, &is_insensitive); 33164445fffbSMatthew Ahrens if (error != 0) { 33174445fffbSMatthew Ahrens nvlist_free(zct.zct_zplprops); 3318da6c28aaSamw return (error); 3319da6c28aaSamw } 33204445fffbSMatthew Ahrens } 3321ab04eb8eStimh 3322*eb633035STom Caputi error = dsl_crypto_params_create_nvlist(DCP_CMD_NONE, nvprops, 3323*eb633035STom Caputi hidden_args, &dcp); 3324*eb633035STom Caputi if (error != 0) { 3325*eb633035STom Caputi nvlist_free(zct.zct_zplprops); 3326*eb633035STom Caputi return (error); 3327*eb633035STom Caputi } 3328*eb633035STom Caputi 33294445fffbSMatthew Ahrens error = dmu_objset_create(fsname, type, 3330*eb633035STom Caputi is_insensitive ? DS_FLAG_CI_DATASET : 0, dcp, cbfunc, &zct); 3331*eb633035STom Caputi 33324445fffbSMatthew Ahrens nvlist_free(zct.zct_zplprops); 3333*eb633035STom Caputi dsl_crypto_params_free(dcp, !!error); 33345c5460e9Seschrock 33354445fffbSMatthew Ahrens /* 33364445fffbSMatthew Ahrens * It would be nice to do this atomically. 33374445fffbSMatthew Ahrens */ 33384445fffbSMatthew Ahrens if (error == 0) { 33394445fffbSMatthew Ahrens error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, 33404445fffbSMatthew Ahrens nvprops, outnvl); 33414445fffbSMatthew Ahrens if (error != 0) 33423b2aab18SMatthew Ahrens (void) dsl_destroy_head(fsname); 33434445fffbSMatthew Ahrens } 33444445fffbSMatthew Ahrens return (error); 33454445fffbSMatthew Ahrens } 3346e9dbad6fSeschrock 33474445fffbSMatthew Ahrens /* 33484445fffbSMatthew Ahrens * innvl: { 33494445fffbSMatthew Ahrens * "origin" -> name of origin snapshot 33504445fffbSMatthew Ahrens * (optional) "props" -> { prop -> value } 3351*eb633035STom Caputi * (optional) "hidden_args" -> { "wkeydata" -> value } 3352*eb633035STom Caputi * raw uint8_t array of encryption wrapping key data (32 bytes) 33534445fffbSMatthew Ahrens * } 33544445fffbSMatthew Ahrens * 33554445fffbSMatthew Ahrens * outnvl: propname -> error code (int32) 33564445fffbSMatthew Ahrens */ 33574445fffbSMatthew Ahrens static int 33584445fffbSMatthew Ahrens zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 33594445fffbSMatthew Ahrens { 33604445fffbSMatthew Ahrens int error = 0; 33614445fffbSMatthew Ahrens nvlist_t *nvprops = NULL; 33624445fffbSMatthew Ahrens char *origin_name; 3363e9dbad6fSeschrock 33644445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "origin", &origin_name) != 0) 3365be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 33664445fffbSMatthew Ahrens (void) nvlist_lookup_nvlist(innvl, "props", &nvprops); 3367e9dbad6fSeschrock 33684445fffbSMatthew Ahrens if (strchr(fsname, '@') || 33694445fffbSMatthew Ahrens strchr(fsname, '%')) 3370be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3371e9dbad6fSeschrock 33724445fffbSMatthew Ahrens if (dataset_namecheck(origin_name, NULL, NULL) != 0) 3373be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3374*eb633035STom Caputi 33753b2aab18SMatthew Ahrens error = dmu_objset_clone(fsname, origin_name); 3376e9dbad6fSeschrock 3377e9dbad6fSeschrock /* 3378e9dbad6fSeschrock * It would be nice to do this atomically. 3379e9dbad6fSeschrock */ 3380e9dbad6fSeschrock if (error == 0) { 33814445fffbSMatthew Ahrens error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, 33824445fffbSMatthew Ahrens nvprops, outnvl); 338392241e0bSTom Erickson if (error != 0) 33843b2aab18SMatthew Ahrens (void) dsl_destroy_head(fsname); 3385e9dbad6fSeschrock } 3386fa9e4066Sahrens return (error); 3387fa9e4066Sahrens } 3388fa9e4066Sahrens 33895cabbc6bSPrashanth Sreenivasa /* ARGSUSED */ 33905cabbc6bSPrashanth Sreenivasa static int 33915cabbc6bSPrashanth Sreenivasa zfs_ioc_remap(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 33925cabbc6bSPrashanth Sreenivasa { 33935cabbc6bSPrashanth Sreenivasa if (strchr(fsname, '@') || 33945cabbc6bSPrashanth Sreenivasa strchr(fsname, '%')) 33955cabbc6bSPrashanth Sreenivasa return (SET_ERROR(EINVAL)); 33965cabbc6bSPrashanth Sreenivasa 33975cabbc6bSPrashanth Sreenivasa return (dmu_objset_remap_indirects(fsname)); 33985cabbc6bSPrashanth Sreenivasa } 33995cabbc6bSPrashanth Sreenivasa 34003cb34c60Sahrens /* 34014445fffbSMatthew Ahrens * innvl: { 34024445fffbSMatthew Ahrens * "snaps" -> { snapshot1, snapshot2 } 34034445fffbSMatthew Ahrens * (optional) "props" -> { prop -> value (string) } 34044445fffbSMatthew Ahrens * } 34054445fffbSMatthew Ahrens * 34064445fffbSMatthew Ahrens * outnvl: snapshot -> error code (int32) 34073cb34c60Sahrens */ 3408fa9e4066Sahrens static int 34094445fffbSMatthew Ahrens zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 3410fa9e4066Sahrens { 34114445fffbSMatthew Ahrens nvlist_t *snaps; 34124445fffbSMatthew Ahrens nvlist_t *props = NULL; 34134445fffbSMatthew Ahrens int error, poollen; 34144445fffbSMatthew Ahrens nvpair_t *pair; 3415bb0ade09Sahrens 34164445fffbSMatthew Ahrens (void) nvlist_lookup_nvlist(innvl, "props", &props); 34174445fffbSMatthew Ahrens if ((error = zfs_check_userprops(poolname, props)) != 0) 34184445fffbSMatthew Ahrens return (error); 34194445fffbSMatthew Ahrens 34204445fffbSMatthew Ahrens if (!nvlist_empty(props) && 34214445fffbSMatthew Ahrens zfs_earlier_version(poolname, SPA_VERSION_SNAP_PROPS)) 3422be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 34234445fffbSMatthew Ahrens 34244445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 3425be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 34264445fffbSMatthew Ahrens poollen = strlen(poolname); 34274445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 34284445fffbSMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 34294445fffbSMatthew Ahrens const char *name = nvpair_name(pair); 34304445fffbSMatthew Ahrens const char *cp = strchr(name, '@'); 3431bb0ade09Sahrens 34324445fffbSMatthew Ahrens /* 34334445fffbSMatthew Ahrens * The snap name must contain an @, and the part after it must 34344445fffbSMatthew Ahrens * contain only valid characters. 34354445fffbSMatthew Ahrens */ 343678f17100SMatthew Ahrens if (cp == NULL || 343778f17100SMatthew Ahrens zfs_component_namecheck(cp + 1, NULL, NULL) != 0) 3438be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3439bb0ade09Sahrens 34404445fffbSMatthew Ahrens /* 34414445fffbSMatthew Ahrens * The snap must be in the specified pool. 34424445fffbSMatthew Ahrens */ 34434445fffbSMatthew Ahrens if (strncmp(name, poolname, poollen) != 0 || 34444445fffbSMatthew Ahrens (name[poollen] != '/' && name[poollen] != '@')) 3445be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 34464445fffbSMatthew Ahrens 34474445fffbSMatthew Ahrens /* This must be the only snap of this fs. */ 34484445fffbSMatthew Ahrens for (nvpair_t *pair2 = nvlist_next_nvpair(snaps, pair); 34494445fffbSMatthew Ahrens pair2 != NULL; pair2 = nvlist_next_nvpair(snaps, pair2)) { 34504445fffbSMatthew Ahrens if (strncmp(name, nvpair_name(pair2), cp - name + 1) 34514445fffbSMatthew Ahrens == 0) { 3452be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 34534445fffbSMatthew Ahrens } 34544445fffbSMatthew Ahrens } 34554445fffbSMatthew Ahrens } 3456bb0ade09Sahrens 34573b2aab18SMatthew Ahrens error = dsl_dataset_snapshot(snaps, props, outnvl); 34584445fffbSMatthew Ahrens return (error); 34594445fffbSMatthew Ahrens } 34604445fffbSMatthew Ahrens 34614445fffbSMatthew Ahrens /* 34624445fffbSMatthew Ahrens * innvl: "message" -> string 34634445fffbSMatthew Ahrens */ 34644445fffbSMatthew Ahrens /* ARGSUSED */ 34654445fffbSMatthew Ahrens static int 34664445fffbSMatthew Ahrens zfs_ioc_log_history(const char *unused, nvlist_t *innvl, nvlist_t *outnvl) 34674445fffbSMatthew Ahrens { 34684445fffbSMatthew Ahrens char *message; 34694445fffbSMatthew Ahrens spa_t *spa; 34704445fffbSMatthew Ahrens int error; 34714445fffbSMatthew Ahrens char *poolname; 34724445fffbSMatthew Ahrens 34734445fffbSMatthew Ahrens /* 34744445fffbSMatthew Ahrens * The poolname in the ioctl is not set, we get it from the TSD, 34754445fffbSMatthew Ahrens * which was set at the end of the last successful ioctl that allows 34764445fffbSMatthew Ahrens * logging. The secpolicy func already checked that it is set. 34774445fffbSMatthew Ahrens * Only one log ioctl is allowed after each successful ioctl, so 34784445fffbSMatthew Ahrens * we clear the TSD here. 34794445fffbSMatthew Ahrens */ 34804445fffbSMatthew Ahrens poolname = tsd_get(zfs_allow_log_key); 34814445fffbSMatthew Ahrens (void) tsd_set(zfs_allow_log_key, NULL); 34824445fffbSMatthew Ahrens error = spa_open(poolname, &spa, FTAG); 34834445fffbSMatthew Ahrens strfree(poolname); 34844445fffbSMatthew Ahrens if (error != 0) 34854445fffbSMatthew Ahrens return (error); 34864445fffbSMatthew Ahrens 34874445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "message", &message) != 0) { 34884445fffbSMatthew Ahrens spa_close(spa, FTAG); 3489be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3490bb0ade09Sahrens } 3491ea2f5b9eSMatthew Ahrens 34924445fffbSMatthew Ahrens if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { 34934445fffbSMatthew Ahrens spa_close(spa, FTAG); 3494be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 34954445fffbSMatthew Ahrens } 3496ea2f5b9eSMatthew Ahrens 34974445fffbSMatthew Ahrens error = spa_history_log(spa, message); 34984445fffbSMatthew Ahrens spa_close(spa, FTAG); 3499bb0ade09Sahrens return (error); 35001d452cf5Sahrens } 3501fa9e4066Sahrens 35023b2aab18SMatthew Ahrens /* 35033b2aab18SMatthew Ahrens * The dp_config_rwlock must not be held when calling this, because the 35043b2aab18SMatthew Ahrens * unmount may need to write out data. 35053b2aab18SMatthew Ahrens * 35063b2aab18SMatthew Ahrens * This function is best-effort. Callers must deal gracefully if it 35073b2aab18SMatthew Ahrens * remains mounted (or is remounted after this call). 3508fc7a6e3fSWill Andrews * 3509fc7a6e3fSWill Andrews * Returns 0 if the argument is not a snapshot, or it is not currently a 3510fc7a6e3fSWill Andrews * filesystem, or we were able to unmount it. Returns error code otherwise. 35113b2aab18SMatthew Ahrens */ 3512ed992b0aSSerapheim Dimitropoulos void 35133b2aab18SMatthew Ahrens zfs_unmount_snap(const char *snapname) 35141d452cf5Sahrens { 3515ed992b0aSSerapheim Dimitropoulos vfs_t *vfsp = NULL; 3516ed992b0aSSerapheim Dimitropoulos zfsvfs_t *zfsvfs = NULL; 35171d452cf5Sahrens 35183b2aab18SMatthew Ahrens if (strchr(snapname, '@') == NULL) 3519ed992b0aSSerapheim Dimitropoulos return; 35201d452cf5Sahrens 3521ed992b0aSSerapheim Dimitropoulos int err = getzfsvfs(snapname, &zfsvfs); 3522ed992b0aSSerapheim Dimitropoulos if (err != 0) { 3523ed992b0aSSerapheim Dimitropoulos ASSERT3P(zfsvfs, ==, NULL); 3524ed992b0aSSerapheim Dimitropoulos return; 3525ed992b0aSSerapheim Dimitropoulos } 3526ed992b0aSSerapheim Dimitropoulos vfsp = zfsvfs->z_vfs; 35273b2aab18SMatthew Ahrens 35283b2aab18SMatthew Ahrens ASSERT(!dsl_pool_config_held(dmu_objset_pool(zfsvfs->z_os))); 35291d452cf5Sahrens 3530fc7a6e3fSWill Andrews err = vn_vfswlock(vfsp->vfs_vnodecovered); 35314445fffbSMatthew Ahrens VFS_RELE(vfsp); 3532fc7a6e3fSWill Andrews if (err != 0) 3533ed992b0aSSerapheim Dimitropoulos return; 35344445fffbSMatthew Ahrens 35354445fffbSMatthew Ahrens /* 35364445fffbSMatthew Ahrens * Always force the unmount for snapshots. 35374445fffbSMatthew Ahrens */ 35383b2aab18SMatthew Ahrens (void) dounmount(vfsp, MS_FORCE, kcred); 35393b2aab18SMatthew Ahrens } 35403b2aab18SMatthew Ahrens 35413b2aab18SMatthew Ahrens /* ARGSUSED */ 35423b2aab18SMatthew Ahrens static int 35433b2aab18SMatthew Ahrens zfs_unmount_snap_cb(const char *snapname, void *arg) 35443b2aab18SMatthew Ahrens { 3545ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(snapname); 3546ed992b0aSSerapheim Dimitropoulos return (0); 35473b2aab18SMatthew Ahrens } 35483b2aab18SMatthew Ahrens 35493b2aab18SMatthew Ahrens /* 35503b2aab18SMatthew Ahrens * When a clone is destroyed, its origin may also need to be destroyed, 35513b2aab18SMatthew Ahrens * in which case it must be unmounted. This routine will do that unmount 35523b2aab18SMatthew Ahrens * if necessary. 35533b2aab18SMatthew Ahrens */ 35543b2aab18SMatthew Ahrens void 35553b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(const char *fsname) 35563b2aab18SMatthew Ahrens { 35573b2aab18SMatthew Ahrens int error; 35583b2aab18SMatthew Ahrens objset_t *os; 35593b2aab18SMatthew Ahrens dsl_dataset_t *ds; 35603b2aab18SMatthew Ahrens 35613b2aab18SMatthew Ahrens error = dmu_objset_hold(fsname, FTAG, &os); 35623b2aab18SMatthew Ahrens if (error != 0) 35633b2aab18SMatthew Ahrens return; 35643b2aab18SMatthew Ahrens ds = dmu_objset_ds(os); 35653b2aab18SMatthew Ahrens if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) { 35669adfa60dSMatthew Ahrens char originname[ZFS_MAX_DATASET_NAME_LEN]; 35673b2aab18SMatthew Ahrens dsl_dataset_name(ds->ds_prev, originname); 35683b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 3569ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(originname); 35703b2aab18SMatthew Ahrens } else { 35713b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 35723b2aab18SMatthew Ahrens } 35731d452cf5Sahrens } 35741d452cf5Sahrens 35753cb34c60Sahrens /* 35764445fffbSMatthew Ahrens * innvl: { 35774445fffbSMatthew Ahrens * "snaps" -> { snapshot1, snapshot2 } 35784445fffbSMatthew Ahrens * (optional boolean) "defer" 35794445fffbSMatthew Ahrens * } 35804445fffbSMatthew Ahrens * 35814445fffbSMatthew Ahrens * outnvl: snapshot -> error code (int32) 35823cb34c60Sahrens * 35833cb34c60Sahrens */ 358478f17100SMatthew Ahrens /* ARGSUSED */ 35851d452cf5Sahrens static int 35864445fffbSMatthew Ahrens zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 35871d452cf5Sahrens { 35884445fffbSMatthew Ahrens nvlist_t *snaps; 358919b94df9SMatthew Ahrens nvpair_t *pair; 35904445fffbSMatthew Ahrens boolean_t defer; 35911d452cf5Sahrens 35924445fffbSMatthew Ahrens if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) 3593be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 35944445fffbSMatthew Ahrens defer = nvlist_exists(innvl, "defer"); 359519b94df9SMatthew Ahrens 35964445fffbSMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 35974445fffbSMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 3598ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(nvpair_name(pair)); 359978f17100SMatthew Ahrens } 360078f17100SMatthew Ahrens 360178f17100SMatthew Ahrens return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl)); 360278f17100SMatthew Ahrens } 360378f17100SMatthew Ahrens 360478f17100SMatthew Ahrens /* 360578f17100SMatthew Ahrens * Create bookmarks. Bookmark names are of the form <fs>#<bmark>. 360678f17100SMatthew Ahrens * All bookmarks must be in the same pool. 360778f17100SMatthew Ahrens * 360878f17100SMatthew Ahrens * innvl: { 360978f17100SMatthew Ahrens * bookmark1 -> snapshot1, bookmark2 -> snapshot2 361078f17100SMatthew Ahrens * } 361178f17100SMatthew Ahrens * 361278f17100SMatthew Ahrens * outnvl: bookmark -> error code (int32) 361378f17100SMatthew Ahrens * 361478f17100SMatthew Ahrens */ 361578f17100SMatthew Ahrens /* ARGSUSED */ 361678f17100SMatthew Ahrens static int 361778f17100SMatthew Ahrens zfs_ioc_bookmark(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 361878f17100SMatthew Ahrens { 361978f17100SMatthew Ahrens for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL); 362078f17100SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) { 362178f17100SMatthew Ahrens char *snap_name; 362278f17100SMatthew Ahrens 362378f17100SMatthew Ahrens /* 362478f17100SMatthew Ahrens * Verify the snapshot argument. 362578f17100SMatthew Ahrens */ 362678f17100SMatthew Ahrens if (nvpair_value_string(pair, &snap_name) != 0) 362778f17100SMatthew Ahrens return (SET_ERROR(EINVAL)); 362878f17100SMatthew Ahrens 362978f17100SMatthew Ahrens 363078f17100SMatthew Ahrens /* Verify that the keys (bookmarks) are unique */ 363178f17100SMatthew Ahrens for (nvpair_t *pair2 = nvlist_next_nvpair(innvl, pair); 363278f17100SMatthew Ahrens pair2 != NULL; pair2 = nvlist_next_nvpair(innvl, pair2)) { 363378f17100SMatthew Ahrens if (strcmp(nvpair_name(pair), nvpair_name(pair2)) == 0) 363478f17100SMatthew Ahrens return (SET_ERROR(EINVAL)); 363578f17100SMatthew Ahrens } 363678f17100SMatthew Ahrens } 363778f17100SMatthew Ahrens 363878f17100SMatthew Ahrens return (dsl_bookmark_create(innvl, outnvl)); 363978f17100SMatthew Ahrens } 364078f17100SMatthew Ahrens 364178f17100SMatthew Ahrens /* 364278f17100SMatthew Ahrens * innvl: { 364378f17100SMatthew Ahrens * property 1, property 2, ... 364478f17100SMatthew Ahrens * } 364578f17100SMatthew Ahrens * 364678f17100SMatthew Ahrens * outnvl: { 364778f17100SMatthew Ahrens * bookmark name 1 -> { property 1, property 2, ... }, 364878f17100SMatthew Ahrens * bookmark name 2 -> { property 1, property 2, ... } 364978f17100SMatthew Ahrens * } 365078f17100SMatthew Ahrens * 365178f17100SMatthew Ahrens */ 365278f17100SMatthew Ahrens static int 365378f17100SMatthew Ahrens zfs_ioc_get_bookmarks(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 365478f17100SMatthew Ahrens { 365578f17100SMatthew Ahrens return (dsl_get_bookmarks(fsname, innvl, outnvl)); 365678f17100SMatthew Ahrens } 365778f17100SMatthew Ahrens 365878f17100SMatthew Ahrens /* 365978f17100SMatthew Ahrens * innvl: { 366078f17100SMatthew Ahrens * bookmark name 1, bookmark name 2 366178f17100SMatthew Ahrens * } 366278f17100SMatthew Ahrens * 366378f17100SMatthew Ahrens * outnvl: bookmark -> error code (int32) 366478f17100SMatthew Ahrens * 366578f17100SMatthew Ahrens */ 366678f17100SMatthew Ahrens static int 366778f17100SMatthew Ahrens zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl, 366878f17100SMatthew Ahrens nvlist_t *outnvl) 366978f17100SMatthew Ahrens { 367078f17100SMatthew Ahrens int error, poollen; 367178f17100SMatthew Ahrens 367278f17100SMatthew Ahrens poollen = strlen(poolname); 367378f17100SMatthew Ahrens for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL); 367478f17100SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) { 367519b94df9SMatthew Ahrens const char *name = nvpair_name(pair); 367678f17100SMatthew Ahrens const char *cp = strchr(name, '#'); 36774445fffbSMatthew Ahrens 367819b94df9SMatthew Ahrens /* 367978f17100SMatthew Ahrens * The bookmark name must contain an #, and the part after it 368078f17100SMatthew Ahrens * must contain only valid characters. 368178f17100SMatthew Ahrens */ 368278f17100SMatthew Ahrens if (cp == NULL || 368378f17100SMatthew Ahrens zfs_component_namecheck(cp + 1, NULL, NULL) != 0) 368478f17100SMatthew Ahrens return (SET_ERROR(EINVAL)); 368578f17100SMatthew Ahrens 368678f17100SMatthew Ahrens /* 368778f17100SMatthew Ahrens * The bookmark must be in the specified pool. 368819b94df9SMatthew Ahrens */ 36894445fffbSMatthew Ahrens if (strncmp(name, poolname, poollen) != 0 || 369078f17100SMatthew Ahrens (name[poollen] != '/' && name[poollen] != '#')) 3691be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 369219b94df9SMatthew Ahrens } 369319b94df9SMatthew Ahrens 369478f17100SMatthew Ahrens error = dsl_bookmark_destroy(innvl, outnvl); 369578f17100SMatthew Ahrens return (error); 36961d452cf5Sahrens } 36971d452cf5Sahrens 3698dfc11533SChris Williamson static int 3699dfc11533SChris Williamson zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl, 3700dfc11533SChris Williamson nvlist_t *outnvl) 3701dfc11533SChris Williamson { 3702dfc11533SChris Williamson char *program; 3703dfc11533SChris Williamson uint64_t instrlimit, memlimit; 3704a3b28680SSerapheim Dimitropoulos boolean_t sync_flag; 3705dfc11533SChris Williamson nvpair_t *nvarg = NULL; 3706dfc11533SChris Williamson 3707dfc11533SChris Williamson if (0 != nvlist_lookup_string(innvl, ZCP_ARG_PROGRAM, &program)) { 3708dfc11533SChris Williamson return (EINVAL); 3709dfc11533SChris Williamson } 3710a3b28680SSerapheim Dimitropoulos if (0 != nvlist_lookup_boolean_value(innvl, ZCP_ARG_SYNC, &sync_flag)) { 3711a3b28680SSerapheim Dimitropoulos sync_flag = B_TRUE; 3712a3b28680SSerapheim Dimitropoulos } 3713dfc11533SChris Williamson if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_INSTRLIMIT, &instrlimit)) { 3714dfc11533SChris Williamson instrlimit = ZCP_DEFAULT_INSTRLIMIT; 3715dfc11533SChris Williamson } 3716dfc11533SChris Williamson if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_MEMLIMIT, &memlimit)) { 3717dfc11533SChris Williamson memlimit = ZCP_DEFAULT_MEMLIMIT; 3718dfc11533SChris Williamson } 3719dfc11533SChris Williamson if (0 != nvlist_lookup_nvpair(innvl, ZCP_ARG_ARGLIST, &nvarg)) { 3720dfc11533SChris Williamson return (EINVAL); 3721dfc11533SChris Williamson } 3722dfc11533SChris Williamson 3723dfc11533SChris Williamson if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit) 3724dfc11533SChris Williamson return (EINVAL); 37252840dce1SChris Williamson if (memlimit == 0 || memlimit > zfs_lua_max_memlimit) 3726dfc11533SChris Williamson return (EINVAL); 3727dfc11533SChris Williamson 3728a3b28680SSerapheim Dimitropoulos return (zcp_eval(poolname, program, sync_flag, instrlimit, memlimit, 3729dfc11533SChris Williamson nvarg, outnvl)); 3730dfc11533SChris Williamson } 3731dfc11533SChris Williamson 373286714001SSerapheim Dimitropoulos /* 373386714001SSerapheim Dimitropoulos * innvl: unused 373486714001SSerapheim Dimitropoulos * outnvl: empty 373586714001SSerapheim Dimitropoulos */ 373686714001SSerapheim Dimitropoulos /* ARGSUSED */ 373786714001SSerapheim Dimitropoulos static int 373886714001SSerapheim Dimitropoulos zfs_ioc_pool_checkpoint(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 373986714001SSerapheim Dimitropoulos { 374086714001SSerapheim Dimitropoulos return (spa_checkpoint(poolname)); 374186714001SSerapheim Dimitropoulos } 374286714001SSerapheim Dimitropoulos 374386714001SSerapheim Dimitropoulos /* 374486714001SSerapheim Dimitropoulos * innvl: unused 374586714001SSerapheim Dimitropoulos * outnvl: empty 374686714001SSerapheim Dimitropoulos */ 374786714001SSerapheim Dimitropoulos /* ARGSUSED */ 374886714001SSerapheim Dimitropoulos static int 374986714001SSerapheim Dimitropoulos zfs_ioc_pool_discard_checkpoint(const char *poolname, nvlist_t *innvl, 375086714001SSerapheim Dimitropoulos nvlist_t *outnvl) 375186714001SSerapheim Dimitropoulos { 375286714001SSerapheim Dimitropoulos return (spa_checkpoint_discard(poolname)); 375386714001SSerapheim Dimitropoulos } 375486714001SSerapheim Dimitropoulos 37553cb34c60Sahrens /* 37563cb34c60Sahrens * inputs: 37573cb34c60Sahrens * zc_name name of dataset to destroy 3758842727c2SChris Kirby * zc_defer_destroy mark for deferred destroy 37593cb34c60Sahrens * 37603cb34c60Sahrens * outputs: none 37613cb34c60Sahrens */ 37621d452cf5Sahrens static int 37631d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc) 37641d452cf5Sahrens { 3765049ba636SAndriy Gapon objset_t *os; 3766049ba636SAndriy Gapon dmu_objset_type_t ost; 3767681d9761SEric Taylor int err; 3768fc7a6e3fSWill Andrews 3769049ba636SAndriy Gapon err = dmu_objset_hold(zc->zc_name, FTAG, &os); 3770049ba636SAndriy Gapon if (err != 0) 3771049ba636SAndriy Gapon return (err); 3772049ba636SAndriy Gapon ost = dmu_objset_type(os); 3773049ba636SAndriy Gapon dmu_objset_rele(os, FTAG); 3774049ba636SAndriy Gapon 3775049ba636SAndriy Gapon if (ost == DMU_OST_ZFS) 3776ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(zc->zc_name); 3777fa9e4066Sahrens 37783b2aab18SMatthew Ahrens if (strchr(zc->zc_name, '@')) 37793b2aab18SMatthew Ahrens err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy); 37803b2aab18SMatthew Ahrens else 37813b2aab18SMatthew Ahrens err = dsl_destroy_head(zc->zc_name); 3782049ba636SAndriy Gapon if (ost == DMU_OST_ZVOL && err == 0) 37835c987a37SChris Kirby (void) zvol_remove_minor(zc->zc_name); 3784681d9761SEric Taylor return (err); 3785fa9e4066Sahrens } 3786fa9e4066Sahrens 3787094e47e9SGeorge Wilson /* 3788094e47e9SGeorge Wilson * innvl: { 3789094e47e9SGeorge Wilson * vdevs: { 3790094e47e9SGeorge Wilson * guid 1, guid 2, ... 3791094e47e9SGeorge Wilson * }, 3792094e47e9SGeorge Wilson * func: POOL_INITIALIZE_{CANCEL|DO|SUSPEND} 3793094e47e9SGeorge Wilson * } 3794094e47e9SGeorge Wilson * 3795094e47e9SGeorge Wilson * outnvl: { 3796094e47e9SGeorge Wilson * [func: EINVAL (if provided command type didn't make sense)], 3797094e47e9SGeorge Wilson * [vdevs: { 3798094e47e9SGeorge Wilson * guid1: errno, (see function body for possible errnos) 3799094e47e9SGeorge Wilson * ... 3800094e47e9SGeorge Wilson * }] 3801094e47e9SGeorge Wilson * } 3802094e47e9SGeorge Wilson * 3803094e47e9SGeorge Wilson */ 3804094e47e9SGeorge Wilson static int 3805094e47e9SGeorge Wilson zfs_ioc_pool_initialize(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) 3806094e47e9SGeorge Wilson { 3807094e47e9SGeorge Wilson spa_t *spa; 3808094e47e9SGeorge Wilson int error; 3809094e47e9SGeorge Wilson 3810094e47e9SGeorge Wilson error = spa_open(poolname, &spa, FTAG); 3811094e47e9SGeorge Wilson if (error != 0) 3812094e47e9SGeorge Wilson return (error); 3813094e47e9SGeorge Wilson 3814094e47e9SGeorge Wilson uint64_t cmd_type; 3815094e47e9SGeorge Wilson if (nvlist_lookup_uint64(innvl, ZPOOL_INITIALIZE_COMMAND, 3816094e47e9SGeorge Wilson &cmd_type) != 0) { 3817094e47e9SGeorge Wilson spa_close(spa, FTAG); 3818094e47e9SGeorge Wilson return (SET_ERROR(EINVAL)); 3819094e47e9SGeorge Wilson } 3820094e47e9SGeorge Wilson if (!(cmd_type == POOL_INITIALIZE_CANCEL || 3821094e47e9SGeorge Wilson cmd_type == POOL_INITIALIZE_DO || 3822094e47e9SGeorge Wilson cmd_type == POOL_INITIALIZE_SUSPEND)) { 3823094e47e9SGeorge Wilson spa_close(spa, FTAG); 3824094e47e9SGeorge Wilson return (SET_ERROR(EINVAL)); 3825094e47e9SGeorge Wilson } 3826094e47e9SGeorge Wilson 3827094e47e9SGeorge Wilson nvlist_t *vdev_guids; 3828094e47e9SGeorge Wilson if (nvlist_lookup_nvlist(innvl, ZPOOL_INITIALIZE_VDEVS, 3829094e47e9SGeorge Wilson &vdev_guids) != 0) { 3830094e47e9SGeorge Wilson spa_close(spa, FTAG); 3831094e47e9SGeorge Wilson return (SET_ERROR(EINVAL)); 3832094e47e9SGeorge Wilson } 3833094e47e9SGeorge Wilson 3834094e47e9SGeorge Wilson nvlist_t *vdev_errlist = fnvlist_alloc(); 3835094e47e9SGeorge Wilson int total_errors = 0; 3836094e47e9SGeorge Wilson 3837094e47e9SGeorge Wilson for (nvpair_t *pair = nvlist_next_nvpair(vdev_guids, NULL); 3838094e47e9SGeorge Wilson pair != NULL; pair = nvlist_next_nvpair(vdev_guids, pair)) { 3839094e47e9SGeorge Wilson uint64_t vdev_guid = fnvpair_value_uint64(pair); 3840094e47e9SGeorge Wilson 3841094e47e9SGeorge Wilson error = spa_vdev_initialize(spa, vdev_guid, cmd_type); 3842094e47e9SGeorge Wilson if (error != 0) { 3843094e47e9SGeorge Wilson char guid_as_str[MAXNAMELEN]; 3844094e47e9SGeorge Wilson 3845094e47e9SGeorge Wilson (void) snprintf(guid_as_str, sizeof (guid_as_str), 3846094e47e9SGeorge Wilson "%llu", (unsigned long long)vdev_guid); 3847094e47e9SGeorge Wilson fnvlist_add_int64(vdev_errlist, guid_as_str, error); 3848094e47e9SGeorge Wilson total_errors++; 3849094e47e9SGeorge Wilson } 3850094e47e9SGeorge Wilson } 3851094e47e9SGeorge Wilson if (fnvlist_size(vdev_errlist) > 0) { 3852094e47e9SGeorge Wilson fnvlist_add_nvlist(outnvl, ZPOOL_INITIALIZE_VDEVS, 3853094e47e9SGeorge Wilson vdev_errlist); 3854094e47e9SGeorge Wilson } 3855094e47e9SGeorge Wilson fnvlist_free(vdev_errlist); 3856094e47e9SGeorge Wilson 3857094e47e9SGeorge Wilson spa_close(spa, FTAG); 3858094e47e9SGeorge Wilson return (total_errors > 0 ? EINVAL : 0); 3859094e47e9SGeorge Wilson } 3860094e47e9SGeorge Wilson 38613cb34c60Sahrens /* 3862a7027df1SMatthew Ahrens * fsname is name of dataset to rollback (to most recent snapshot) 38633cb34c60Sahrens * 386477b17137SAndriy Gapon * innvl may contain name of expected target snapshot 3865a7027df1SMatthew Ahrens * 3866a7027df1SMatthew Ahrens * outnvl: "target" -> name of most recent snapshot 3867a7027df1SMatthew Ahrens * } 38683cb34c60Sahrens */ 3869a7027df1SMatthew Ahrens /* ARGSUSED */ 3870fa9e4066Sahrens static int 387177b17137SAndriy Gapon zfs_ioc_rollback(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) 3872fa9e4066Sahrens { 3873ae46e4c7SMatthew Ahrens zfsvfs_t *zfsvfs; 387477b17137SAndriy Gapon char *target = NULL; 38753b2aab18SMatthew Ahrens int error; 3876ae46e4c7SMatthew Ahrens 387777b17137SAndriy Gapon (void) nvlist_lookup_string(innvl, "target", &target); 387877b17137SAndriy Gapon if (target != NULL) { 387995643f75SAndriy Gapon const char *cp = strchr(target, '@'); 388077b17137SAndriy Gapon 388195643f75SAndriy Gapon /* 388295643f75SAndriy Gapon * The snap name must contain an @, and the part after it must 388395643f75SAndriy Gapon * contain only valid characters. 388495643f75SAndriy Gapon */ 388595643f75SAndriy Gapon if (cp == NULL || 388695643f75SAndriy Gapon zfs_component_namecheck(cp + 1, NULL, NULL) != 0) 388777b17137SAndriy Gapon return (SET_ERROR(EINVAL)); 388877b17137SAndriy Gapon } 388977b17137SAndriy Gapon 3890a7027df1SMatthew Ahrens if (getzfsvfs(fsname, &zfsvfs) == 0) { 3891690041b9SAndriy Gapon dsl_dataset_t *ds; 3892690041b9SAndriy Gapon 3893690041b9SAndriy Gapon ds = dmu_objset_ds(zfsvfs->z_os); 3894503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 389547f263f4Sek if (error == 0) { 389647f263f4Sek int resume_err; 38974ccbb6e7Sahrens 389877b17137SAndriy Gapon error = dsl_dataset_rollback(fsname, target, zfsvfs, 389977b17137SAndriy Gapon outnvl); 3900690041b9SAndriy Gapon resume_err = zfs_resume_fs(zfsvfs, ds); 390147f263f4Sek error = error ? error : resume_err; 390247f263f4Sek } 39034ccbb6e7Sahrens VFS_RELE(zfsvfs->z_vfs); 39044ccbb6e7Sahrens } else { 390577b17137SAndriy Gapon error = dsl_dataset_rollback(fsname, target, NULL, outnvl); 39064ccbb6e7Sahrens } 39073b2aab18SMatthew Ahrens return (error); 39083b2aab18SMatthew Ahrens } 39094ccbb6e7Sahrens 39103b2aab18SMatthew Ahrens static int 39113b2aab18SMatthew Ahrens recursive_unmount(const char *fsname, void *arg) 39123b2aab18SMatthew Ahrens { 39133b2aab18SMatthew Ahrens const char *snapname = arg; 39149adfa60dSMatthew Ahrens char fullname[ZFS_MAX_DATASET_NAME_LEN]; 3915ae46e4c7SMatthew Ahrens 39163b2aab18SMatthew Ahrens (void) snprintf(fullname, sizeof (fullname), "%s@%s", fsname, snapname); 3917ed992b0aSSerapheim Dimitropoulos zfs_unmount_snap(fullname); 3918ed992b0aSSerapheim Dimitropoulos 3919ed992b0aSSerapheim Dimitropoulos return (0); 3920fa9e4066Sahrens } 3921fa9e4066Sahrens 39223cb34c60Sahrens /* 39233cb34c60Sahrens * inputs: 39243cb34c60Sahrens * zc_name old name of dataset 39253cb34c60Sahrens * zc_value new name of dataset 39263cb34c60Sahrens * zc_cookie recursive flag (only valid for snapshots) 39273cb34c60Sahrens * 39283cb34c60Sahrens * outputs: none 39293cb34c60Sahrens */ 3930fa9e4066Sahrens static int 3931fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc) 3932fa9e4066Sahrens { 3933049ba636SAndriy Gapon objset_t *os; 3934049ba636SAndriy Gapon dmu_objset_type_t ost; 39357f1f55eaSvb boolean_t recursive = zc->zc_cookie & 1; 39363b2aab18SMatthew Ahrens char *at; 3937049ba636SAndriy Gapon int err; 3938cdf5b4caSmmusante 3939add927f8Sloli /* "zfs rename" from and to ...%recv datasets should both fail */ 3940add927f8Sloli zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 3941e9dbad6fSeschrock zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 3942add927f8Sloli if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 || 3943add927f8Sloli dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 3944add927f8Sloli strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%')) 3945be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 3946fa9e4066Sahrens 3947049ba636SAndriy Gapon err = dmu_objset_hold(zc->zc_name, FTAG, &os); 3948049ba636SAndriy Gapon if (err != 0) 3949049ba636SAndriy Gapon return (err); 3950049ba636SAndriy Gapon ost = dmu_objset_type(os); 3951049ba636SAndriy Gapon dmu_objset_rele(os, FTAG); 3952049ba636SAndriy Gapon 39533b2aab18SMatthew Ahrens at = strchr(zc->zc_name, '@'); 39543b2aab18SMatthew Ahrens if (at != NULL) { 39553b2aab18SMatthew Ahrens /* snaps must be in same fs */ 3956a0c1127bSSteven Hartland int error; 3957a0c1127bSSteven Hartland 39583b2aab18SMatthew Ahrens if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) 3959be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 39603b2aab18SMatthew Ahrens *at = '\0'; 3961049ba636SAndriy Gapon if (ost == DMU_OST_ZFS) { 3962a0c1127bSSteven Hartland error = dmu_objset_find(zc->zc_name, 39633b2aab18SMatthew Ahrens recursive_unmount, at + 1, 39643b2aab18SMatthew Ahrens recursive ? DS_FIND_CHILDREN : 0); 3965a0c1127bSSteven Hartland if (error != 0) { 3966a0c1127bSSteven Hartland *at = '@'; 39673b2aab18SMatthew Ahrens return (error); 3968a0c1127bSSteven Hartland } 39693b2aab18SMatthew Ahrens } 3970a0c1127bSSteven Hartland error = dsl_dataset_rename_snapshot(zc->zc_name, 3971a0c1127bSSteven Hartland at + 1, strchr(zc->zc_value, '@') + 1, recursive); 3972a0c1127bSSteven Hartland *at = '@'; 3973a0c1127bSSteven Hartland 3974a0c1127bSSteven Hartland return (error); 39753b2aab18SMatthew Ahrens } else { 3976049ba636SAndriy Gapon if (ost == DMU_OST_ZVOL) 39773b2aab18SMatthew Ahrens (void) zvol_remove_minor(zc->zc_name); 39783b2aab18SMatthew Ahrens return (dsl_dir_rename(zc->zc_name, zc->zc_value)); 3979fa9e4066Sahrens } 3980fa9e4066Sahrens } 3981fa9e4066Sahrens 398292241e0bSTom Erickson static int 398392241e0bSTom Erickson zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) 398492241e0bSTom Erickson { 398592241e0bSTom Erickson const char *propname = nvpair_name(pair); 398692241e0bSTom Erickson boolean_t issnap = (strchr(dsname, '@') != NULL); 398792241e0bSTom Erickson zfs_prop_t prop = zfs_name_to_prop(propname); 398892241e0bSTom Erickson uint64_t intval; 398992241e0bSTom Erickson int err; 399092241e0bSTom Erickson 399192241e0bSTom Erickson if (prop == ZPROP_INVAL) { 399292241e0bSTom Erickson if (zfs_prop_user(propname)) { 399392241e0bSTom Erickson if (err = zfs_secpolicy_write_perms(dsname, 399492241e0bSTom Erickson ZFS_DELEG_PERM_USERPROP, cr)) 399592241e0bSTom Erickson return (err); 399692241e0bSTom Erickson return (0); 399792241e0bSTom Erickson } 399892241e0bSTom Erickson 399992241e0bSTom Erickson if (!issnap && zfs_prop_userquota(propname)) { 400092241e0bSTom Erickson const char *perm = NULL; 400192241e0bSTom Erickson const char *uq_prefix = 400292241e0bSTom Erickson zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA]; 400392241e0bSTom Erickson const char *gq_prefix = 400492241e0bSTom Erickson zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA]; 400592241e0bSTom Erickson 400692241e0bSTom Erickson if (strncmp(propname, uq_prefix, 400792241e0bSTom Erickson strlen(uq_prefix)) == 0) { 400892241e0bSTom Erickson perm = ZFS_DELEG_PERM_USERQUOTA; 400992241e0bSTom Erickson } else if (strncmp(propname, gq_prefix, 401092241e0bSTom Erickson strlen(gq_prefix)) == 0) { 401192241e0bSTom Erickson perm = ZFS_DELEG_PERM_GROUPQUOTA; 401292241e0bSTom Erickson } else { 401392241e0bSTom Erickson /* USERUSED and GROUPUSED are read-only */ 4014be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 401592241e0bSTom Erickson } 401692241e0bSTom Erickson 401792241e0bSTom Erickson if (err = zfs_secpolicy_write_perms(dsname, perm, cr)) 401892241e0bSTom Erickson return (err); 401992241e0bSTom Erickson return (0); 402092241e0bSTom Erickson } 402192241e0bSTom Erickson 4022be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 402392241e0bSTom Erickson } 402492241e0bSTom Erickson 402592241e0bSTom Erickson if (issnap) 4026be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 402792241e0bSTom Erickson 402892241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_NVLIST) { 402992241e0bSTom Erickson /* 403092241e0bSTom Erickson * dsl_prop_get_all_impl() returns properties in this 403192241e0bSTom Erickson * format. 403292241e0bSTom Erickson */ 403392241e0bSTom Erickson nvlist_t *attrs; 403492241e0bSTom Erickson VERIFY(nvpair_value_nvlist(pair, &attrs) == 0); 403592241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 403692241e0bSTom Erickson &pair) == 0); 403792241e0bSTom Erickson } 403892241e0bSTom Erickson 403992241e0bSTom Erickson /* 404092241e0bSTom Erickson * Check that this value is valid for this pool version 404192241e0bSTom Erickson */ 404292241e0bSTom Erickson switch (prop) { 404392241e0bSTom Erickson case ZFS_PROP_COMPRESSION: 404492241e0bSTom Erickson /* 404592241e0bSTom Erickson * If the user specified gzip compression, make sure 404692241e0bSTom Erickson * the SPA supports it. We ignore any errors here since 404792241e0bSTom Erickson * we'll catch them later. 404892241e0bSTom Erickson */ 4049b5152584SMatthew Ahrens if (nvpair_value_uint64(pair, &intval) == 0) { 405092241e0bSTom Erickson if (intval >= ZIO_COMPRESS_GZIP_1 && 405192241e0bSTom Erickson intval <= ZIO_COMPRESS_GZIP_9 && 405292241e0bSTom Erickson zfs_earlier_version(dsname, 405392241e0bSTom Erickson SPA_VERSION_GZIP_COMPRESSION)) { 4054be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 405592241e0bSTom Erickson } 405692241e0bSTom Erickson 405792241e0bSTom Erickson if (intval == ZIO_COMPRESS_ZLE && 405892241e0bSTom Erickson zfs_earlier_version(dsname, 405992241e0bSTom Erickson SPA_VERSION_ZLE_COMPRESSION)) 4060be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 406192241e0bSTom Erickson 4062a6f561b4SSašo Kiselkov if (intval == ZIO_COMPRESS_LZ4) { 4063a6f561b4SSašo Kiselkov spa_t *spa; 4064a6f561b4SSašo Kiselkov 4065a6f561b4SSašo Kiselkov if ((err = spa_open(dsname, &spa, FTAG)) != 0) 4066a6f561b4SSašo Kiselkov return (err); 4067a6f561b4SSašo Kiselkov 40682acef22dSMatthew Ahrens if (!spa_feature_is_enabled(spa, 40692acef22dSMatthew Ahrens SPA_FEATURE_LZ4_COMPRESS)) { 4070a6f561b4SSašo Kiselkov spa_close(spa, FTAG); 4071be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 4072a6f561b4SSašo Kiselkov } 4073a6f561b4SSašo Kiselkov spa_close(spa, FTAG); 4074a6f561b4SSašo Kiselkov } 4075a6f561b4SSašo Kiselkov 407692241e0bSTom Erickson /* 407792241e0bSTom Erickson * If this is a bootable dataset then 407892241e0bSTom Erickson * verify that the compression algorithm 407992241e0bSTom Erickson * is supported for booting. We must return 408092241e0bSTom Erickson * something other than ENOTSUP since it 408192241e0bSTom Erickson * implies a downrev pool version. 408292241e0bSTom Erickson */ 408392241e0bSTom Erickson if (zfs_is_bootfs(dsname) && 408492241e0bSTom Erickson !BOOTFS_COMPRESS_VALID(intval)) { 4085be6fd75aSMatthew Ahrens return (SET_ERROR(ERANGE)); 408692241e0bSTom Erickson } 408792241e0bSTom Erickson } 408892241e0bSTom Erickson break; 408992241e0bSTom Erickson 409092241e0bSTom Erickson case ZFS_PROP_COPIES: 409192241e0bSTom Erickson if (zfs_earlier_version(dsname, SPA_VERSION_DITTO_BLOCKS)) 4092be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 409392241e0bSTom Erickson break; 409492241e0bSTom Erickson 4095b5152584SMatthew Ahrens case ZFS_PROP_RECORDSIZE: 4096b5152584SMatthew Ahrens /* Record sizes above 128k need the feature to be enabled */ 4097b5152584SMatthew Ahrens if (nvpair_value_uint64(pair, &intval) == 0 && 4098b5152584SMatthew Ahrens intval > SPA_OLD_MAXBLOCKSIZE) { 4099b5152584SMatthew Ahrens spa_t *spa; 4100b5152584SMatthew Ahrens 4101b5152584SMatthew Ahrens /* 4102b5152584SMatthew Ahrens * We don't allow setting the property above 1MB, 4103b5152584SMatthew Ahrens * unless the tunable has been changed. 4104b5152584SMatthew Ahrens */ 4105b5152584SMatthew Ahrens if (intval > zfs_max_recordsize || 4106b5152584SMatthew Ahrens intval > SPA_MAXBLOCKSIZE) 41076de9bb56SMatthew Ahrens return (SET_ERROR(ERANGE)); 4108b5152584SMatthew Ahrens 4109b5152584SMatthew Ahrens if ((err = spa_open(dsname, &spa, FTAG)) != 0) 4110b5152584SMatthew Ahrens return (err); 4111b5152584SMatthew Ahrens 4112b5152584SMatthew Ahrens if (!spa_feature_is_enabled(spa, 4113b5152584SMatthew Ahrens SPA_FEATURE_LARGE_BLOCKS)) { 4114b5152584SMatthew Ahrens spa_close(spa, FTAG); 4115b5152584SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 4116b5152584SMatthew Ahrens } 4117b5152584SMatthew Ahrens spa_close(spa, FTAG); 4118b5152584SMatthew Ahrens } 4119b5152584SMatthew Ahrens break; 4120b5152584SMatthew Ahrens 412154811da5SToomas Soome case ZFS_PROP_DNODESIZE: 412254811da5SToomas Soome /* Dnode sizes above 512 need the feature to be enabled */ 412354811da5SToomas Soome if (nvpair_value_uint64(pair, &intval) == 0 && 412454811da5SToomas Soome intval != ZFS_DNSIZE_LEGACY) { 412554811da5SToomas Soome spa_t *spa; 412654811da5SToomas Soome 412754811da5SToomas Soome if ((err = spa_open(dsname, &spa, FTAG)) != 0) 412854811da5SToomas Soome return (err); 412954811da5SToomas Soome 413054811da5SToomas Soome if (!spa_feature_is_enabled(spa, 413154811da5SToomas Soome SPA_FEATURE_LARGE_DNODE)) { 413254811da5SToomas Soome spa_close(spa, FTAG); 413354811da5SToomas Soome return (SET_ERROR(ENOTSUP)); 413454811da5SToomas Soome } 413554811da5SToomas Soome spa_close(spa, FTAG); 413654811da5SToomas Soome } 413754811da5SToomas Soome break; 413854811da5SToomas Soome 4139663207adSDon Brady case ZFS_PROP_SPECIAL_SMALL_BLOCKS: 4140663207adSDon Brady /* 4141663207adSDon Brady * This property could require the allocation classes 4142663207adSDon Brady * feature to be active for setting, however we allow 4143663207adSDon Brady * it so that tests of settable properties succeed. 4144663207adSDon Brady * The CLI will issue a warning in this case. 4145663207adSDon Brady */ 4146663207adSDon Brady break; 4147663207adSDon Brady 414892241e0bSTom Erickson case ZFS_PROP_SHARESMB: 414992241e0bSTom Erickson if (zpl_earlier_version(dsname, ZPL_VERSION_FUID)) 4150be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 415192241e0bSTom Erickson break; 415292241e0bSTom Erickson 415392241e0bSTom Erickson case ZFS_PROP_ACLINHERIT: 415492241e0bSTom Erickson if (nvpair_type(pair) == DATA_TYPE_UINT64 && 415592241e0bSTom Erickson nvpair_value_uint64(pair, &intval) == 0) { 415692241e0bSTom Erickson if (intval == ZFS_ACL_PASSTHROUGH_X && 415792241e0bSTom Erickson zfs_earlier_version(dsname, 415892241e0bSTom Erickson SPA_VERSION_PASSTHROUGH_X)) 4159be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 416092241e0bSTom Erickson } 416192241e0bSTom Erickson break; 416245818ee1SMatthew Ahrens 416345818ee1SMatthew Ahrens case ZFS_PROP_CHECKSUM: 416445818ee1SMatthew Ahrens case ZFS_PROP_DEDUP: 416545818ee1SMatthew Ahrens { 416645818ee1SMatthew Ahrens spa_feature_t feature; 416745818ee1SMatthew Ahrens spa_t *spa; 416845818ee1SMatthew Ahrens 416945818ee1SMatthew Ahrens /* dedup feature version checks */ 417045818ee1SMatthew Ahrens if (prop == ZFS_PROP_DEDUP && 417145818ee1SMatthew Ahrens zfs_earlier_version(dsname, SPA_VERSION_DEDUP)) 417245818ee1SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 417345818ee1SMatthew Ahrens 417445818ee1SMatthew Ahrens if (nvpair_value_uint64(pair, &intval) != 0) 417545818ee1SMatthew Ahrens return (SET_ERROR(EINVAL)); 417645818ee1SMatthew Ahrens 417745818ee1SMatthew Ahrens /* check prop value is enabled in features */ 4178971640e6Silovezfs feature = zio_checksum_to_feature(intval & ZIO_CHECKSUM_MASK); 417945818ee1SMatthew Ahrens if (feature == SPA_FEATURE_NONE) 418045818ee1SMatthew Ahrens break; 418145818ee1SMatthew Ahrens 418245818ee1SMatthew Ahrens if ((err = spa_open(dsname, &spa, FTAG)) != 0) 418345818ee1SMatthew Ahrens return (err); 41840dd498c0SToomas Soome 418545818ee1SMatthew Ahrens if (!spa_feature_is_enabled(spa, feature)) { 418645818ee1SMatthew Ahrens spa_close(spa, FTAG); 418745818ee1SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 418845818ee1SMatthew Ahrens } 418945818ee1SMatthew Ahrens spa_close(spa, FTAG); 419045818ee1SMatthew Ahrens break; 419145818ee1SMatthew Ahrens } 419292241e0bSTom Erickson } 419392241e0bSTom Erickson 419492241e0bSTom Erickson return (zfs_secpolicy_setprop(dsname, prop, pair, CRED())); 419592241e0bSTom Erickson } 419692241e0bSTom Erickson 4197a6f561b4SSašo Kiselkov /* 4198a6f561b4SSašo Kiselkov * Checks for a race condition to make sure we don't increment a feature flag 4199a6f561b4SSašo Kiselkov * multiple times. 4200a6f561b4SSašo Kiselkov */ 4201a6f561b4SSašo Kiselkov static int 42023b2aab18SMatthew Ahrens zfs_prop_activate_feature_check(void *arg, dmu_tx_t *tx) 4203a6f561b4SSašo Kiselkov { 42043b2aab18SMatthew Ahrens spa_t *spa = dmu_tx_pool(tx)->dp_spa; 42052acef22dSMatthew Ahrens spa_feature_t *featurep = arg; 4206a6f561b4SSašo Kiselkov 42072acef22dSMatthew Ahrens if (!spa_feature_is_active(spa, *featurep)) 4208a6f561b4SSašo Kiselkov return (0); 4209a6f561b4SSašo Kiselkov else 4210be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 4211a6f561b4SSašo Kiselkov } 4212a6f561b4SSašo Kiselkov 4213a6f561b4SSašo Kiselkov /* 4214a6f561b4SSašo Kiselkov * The callback invoked on feature activation in the sync task caused by 4215a6f561b4SSašo Kiselkov * zfs_prop_activate_feature. 4216a6f561b4SSašo Kiselkov */ 4217a6f561b4SSašo Kiselkov static void 42183b2aab18SMatthew Ahrens zfs_prop_activate_feature_sync(void *arg, dmu_tx_t *tx) 4219a6f561b4SSašo Kiselkov { 42203b2aab18SMatthew Ahrens spa_t *spa = dmu_tx_pool(tx)->dp_spa; 42212acef22dSMatthew Ahrens spa_feature_t *featurep = arg; 4222a6f561b4SSašo Kiselkov 42232acef22dSMatthew Ahrens spa_feature_incr(spa, *featurep, tx); 4224a6f561b4SSašo Kiselkov } 4225a6f561b4SSašo Kiselkov 42263b2aab18SMatthew Ahrens /* 42273b2aab18SMatthew Ahrens * Activates a feature on a pool in response to a property setting. This 42283b2aab18SMatthew Ahrens * creates a new sync task which modifies the pool to reflect the feature 42293b2aab18SMatthew Ahrens * as being active. 42303b2aab18SMatthew Ahrens */ 42313b2aab18SMatthew Ahrens static int 42322acef22dSMatthew Ahrens zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature) 42333b2aab18SMatthew Ahrens { 42343b2aab18SMatthew Ahrens int err; 42353b2aab18SMatthew Ahrens 42363b2aab18SMatthew Ahrens /* EBUSY here indicates that the feature is already active */ 42373b2aab18SMatthew Ahrens err = dsl_sync_task(spa_name(spa), 42383b2aab18SMatthew Ahrens zfs_prop_activate_feature_check, zfs_prop_activate_feature_sync, 42397d46dc6cSMatthew Ahrens &feature, 2, ZFS_SPACE_CHECK_RESERVED); 42403b2aab18SMatthew Ahrens 42413b2aab18SMatthew Ahrens if (err != 0 && err != EBUSY) 42423b2aab18SMatthew Ahrens return (err); 42433b2aab18SMatthew Ahrens else 42443b2aab18SMatthew Ahrens return (0); 42453b2aab18SMatthew Ahrens } 42463b2aab18SMatthew Ahrens 424792241e0bSTom Erickson /* 424892241e0bSTom Erickson * Removes properties from the given props list that fail permission checks 424992241e0bSTom Erickson * needed to clear them and to restore them in case of a receive error. For each 425092241e0bSTom Erickson * property, make sure we have both set and inherit permissions. 425192241e0bSTom Erickson * 425292241e0bSTom Erickson * Returns the first error encountered if any permission checks fail. If the 425392241e0bSTom Erickson * caller provides a non-NULL errlist, it also gives the complete list of names 425492241e0bSTom Erickson * of all the properties that failed a permission check along with the 425592241e0bSTom Erickson * corresponding error numbers. The caller is responsible for freeing the 425692241e0bSTom Erickson * returned errlist. 425792241e0bSTom Erickson * 425892241e0bSTom Erickson * If every property checks out successfully, zero is returned and the list 425992241e0bSTom Erickson * pointed at by errlist is NULL. 426092241e0bSTom Erickson */ 426192241e0bSTom Erickson static int 426292241e0bSTom Erickson zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) 4263745cd3c5Smaybee { 4264745cd3c5Smaybee zfs_cmd_t *zc; 426592241e0bSTom Erickson nvpair_t *pair, *next_pair; 426692241e0bSTom Erickson nvlist_t *errors; 426792241e0bSTom Erickson int err, rv = 0; 4268745cd3c5Smaybee 4269745cd3c5Smaybee if (props == NULL) 427092241e0bSTom Erickson return (0); 427192241e0bSTom Erickson 427292241e0bSTom Erickson VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0); 427392241e0bSTom Erickson 4274745cd3c5Smaybee zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP); 4275745cd3c5Smaybee (void) strcpy(zc->zc_name, dataset); 427692241e0bSTom Erickson pair = nvlist_next_nvpair(props, NULL); 427792241e0bSTom Erickson while (pair != NULL) { 427892241e0bSTom Erickson next_pair = nvlist_next_nvpair(props, pair); 427992241e0bSTom Erickson 428092241e0bSTom Erickson (void) strcpy(zc->zc_value, nvpair_name(pair)); 428192241e0bSTom Erickson if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 || 42824445fffbSMatthew Ahrens (err = zfs_secpolicy_inherit_prop(zc, NULL, CRED())) != 0) { 428392241e0bSTom Erickson VERIFY(nvlist_remove_nvpair(props, pair) == 0); 428492241e0bSTom Erickson VERIFY(nvlist_add_int32(errors, 428592241e0bSTom Erickson zc->zc_value, err) == 0); 428692241e0bSTom Erickson } 428792241e0bSTom Erickson pair = next_pair; 4288745cd3c5Smaybee } 4289745cd3c5Smaybee kmem_free(zc, sizeof (zfs_cmd_t)); 429092241e0bSTom Erickson 429192241e0bSTom Erickson if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) { 429292241e0bSTom Erickson nvlist_free(errors); 429392241e0bSTom Erickson errors = NULL; 429492241e0bSTom Erickson } else { 429592241e0bSTom Erickson VERIFY(nvpair_value_int32(pair, &rv) == 0); 429692241e0bSTom Erickson } 429792241e0bSTom Erickson 429892241e0bSTom Erickson if (errlist == NULL) 429992241e0bSTom Erickson nvlist_free(errors); 430092241e0bSTom Erickson else 430192241e0bSTom Erickson *errlist = errors; 430292241e0bSTom Erickson 430392241e0bSTom Erickson return (rv); 430492241e0bSTom Erickson } 430592241e0bSTom Erickson 430692241e0bSTom Erickson static boolean_t 430792241e0bSTom Erickson propval_equals(nvpair_t *p1, nvpair_t *p2) 430892241e0bSTom Erickson { 430992241e0bSTom Erickson if (nvpair_type(p1) == DATA_TYPE_NVLIST) { 431092241e0bSTom Erickson /* dsl_prop_get_all_impl() format */ 431192241e0bSTom Erickson nvlist_t *attrs; 431292241e0bSTom Erickson VERIFY(nvpair_value_nvlist(p1, &attrs) == 0); 431392241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 431492241e0bSTom Erickson &p1) == 0); 431592241e0bSTom Erickson } 431692241e0bSTom Erickson 431792241e0bSTom Erickson if (nvpair_type(p2) == DATA_TYPE_NVLIST) { 431892241e0bSTom Erickson nvlist_t *attrs; 431992241e0bSTom Erickson VERIFY(nvpair_value_nvlist(p2, &attrs) == 0); 432092241e0bSTom Erickson VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE, 432192241e0bSTom Erickson &p2) == 0); 432292241e0bSTom Erickson } 432392241e0bSTom Erickson 432492241e0bSTom Erickson if (nvpair_type(p1) != nvpair_type(p2)) 432592241e0bSTom Erickson return (B_FALSE); 432692241e0bSTom Erickson 432792241e0bSTom Erickson if (nvpair_type(p1) == DATA_TYPE_STRING) { 432892241e0bSTom Erickson char *valstr1, *valstr2; 432992241e0bSTom Erickson 433092241e0bSTom Erickson VERIFY(nvpair_value_string(p1, (char **)&valstr1) == 0); 433192241e0bSTom Erickson VERIFY(nvpair_value_string(p2, (char **)&valstr2) == 0); 433292241e0bSTom Erickson return (strcmp(valstr1, valstr2) == 0); 433392241e0bSTom Erickson } else { 433492241e0bSTom Erickson uint64_t intval1, intval2; 433592241e0bSTom Erickson 433692241e0bSTom Erickson VERIFY(nvpair_value_uint64(p1, &intval1) == 0); 433792241e0bSTom Erickson VERIFY(nvpair_value_uint64(p2, &intval2) == 0); 433892241e0bSTom Erickson return (intval1 == intval2); 433992241e0bSTom Erickson } 4340745cd3c5Smaybee } 4341745cd3c5Smaybee 434292241e0bSTom Erickson /* 434392241e0bSTom Erickson * Remove properties from props if they are not going to change (as determined 434492241e0bSTom Erickson * by comparison with origprops). Remove them from origprops as well, since we 434592241e0bSTom Erickson * do not need to clear or restore properties that won't change. 434692241e0bSTom Erickson */ 434792241e0bSTom Erickson static void 434892241e0bSTom Erickson props_reduce(nvlist_t *props, nvlist_t *origprops) 434992241e0bSTom Erickson { 435092241e0bSTom Erickson nvpair_t *pair, *next_pair; 435192241e0bSTom Erickson 435292241e0bSTom Erickson if (origprops == NULL) 435392241e0bSTom Erickson return; /* all props need to be received */ 435492241e0bSTom Erickson 435592241e0bSTom Erickson pair = nvlist_next_nvpair(props, NULL); 435692241e0bSTom Erickson while (pair != NULL) { 435792241e0bSTom Erickson const char *propname = nvpair_name(pair); 435892241e0bSTom Erickson nvpair_t *match; 435992241e0bSTom Erickson 436092241e0bSTom Erickson next_pair = nvlist_next_nvpair(props, pair); 436192241e0bSTom Erickson 436292241e0bSTom Erickson if ((nvlist_lookup_nvpair(origprops, propname, 436392241e0bSTom Erickson &match) != 0) || !propval_equals(pair, match)) 436492241e0bSTom Erickson goto next; /* need to set received value */ 436592241e0bSTom Erickson 436692241e0bSTom Erickson /* don't clear the existing received value */ 436792241e0bSTom Erickson (void) nvlist_remove_nvpair(origprops, match); 436892241e0bSTom Erickson /* don't bother receiving the property */ 436992241e0bSTom Erickson (void) nvlist_remove_nvpair(props, pair); 437092241e0bSTom Erickson next: 437192241e0bSTom Erickson pair = next_pair; 437292241e0bSTom Erickson } 437392241e0bSTom Erickson } 437492241e0bSTom Erickson 43755878fad7SDan McDonald /* 43765878fad7SDan McDonald * Extract properties that cannot be set PRIOR to the receipt of a dataset. 43775878fad7SDan McDonald * For example, refquota cannot be set until after the receipt of a dataset, 43785878fad7SDan McDonald * because in replication streams, an older/earlier snapshot may exceed the 43795878fad7SDan McDonald * refquota. We want to receive the older/earlier snapshot, but setting 43805878fad7SDan McDonald * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent 43815878fad7SDan McDonald * the older/earlier snapshot from being received (with EDQUOT). 43825878fad7SDan McDonald * 43835878fad7SDan McDonald * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario. 43845878fad7SDan McDonald * 43855878fad7SDan McDonald * libzfs will need to be judicious handling errors encountered by props 43865878fad7SDan McDonald * extracted by this function. 43875878fad7SDan McDonald */ 43885878fad7SDan McDonald static nvlist_t * 43895878fad7SDan McDonald extract_delay_props(nvlist_t *props) 43905878fad7SDan McDonald { 43915878fad7SDan McDonald nvlist_t *delayprops; 43925878fad7SDan McDonald nvpair_t *nvp, *tmp; 4393*eb633035STom Caputi static const zfs_prop_t delayable[] = { 4394*eb633035STom Caputi ZFS_PROP_REFQUOTA, 4395*eb633035STom Caputi ZFS_PROP_KEYLOCATION, 4396*eb633035STom Caputi 0 4397*eb633035STom Caputi }; 43985878fad7SDan McDonald int i; 43995878fad7SDan McDonald 44005878fad7SDan McDonald VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0); 44015878fad7SDan McDonald 44025878fad7SDan McDonald for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL; 44035878fad7SDan McDonald nvp = nvlist_next_nvpair(props, nvp)) { 44045878fad7SDan McDonald /* 44055878fad7SDan McDonald * strcmp() is safe because zfs_prop_to_name() always returns 44065878fad7SDan McDonald * a bounded string. 44075878fad7SDan McDonald */ 44085878fad7SDan McDonald for (i = 0; delayable[i] != 0; i++) { 44095878fad7SDan McDonald if (strcmp(zfs_prop_to_name(delayable[i]), 44105878fad7SDan McDonald nvpair_name(nvp)) == 0) { 44115878fad7SDan McDonald break; 44125878fad7SDan McDonald } 44135878fad7SDan McDonald } 44145878fad7SDan McDonald if (delayable[i] != 0) { 44155878fad7SDan McDonald tmp = nvlist_prev_nvpair(props, nvp); 44165878fad7SDan McDonald VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0); 44175878fad7SDan McDonald VERIFY(nvlist_remove_nvpair(props, nvp) == 0); 44185878fad7SDan McDonald nvp = tmp; 44195878fad7SDan McDonald } 44205878fad7SDan McDonald } 44215878fad7SDan McDonald 44225878fad7SDan McDonald if (nvlist_empty(delayprops)) { 44235878fad7SDan McDonald nvlist_free(delayprops); 44245878fad7SDan McDonald delayprops = NULL; 44255878fad7SDan McDonald } 44265878fad7SDan McDonald return (delayprops); 44275878fad7SDan McDonald } 44285878fad7SDan McDonald 442992241e0bSTom Erickson #ifdef DEBUG 443092241e0bSTom Erickson static boolean_t zfs_ioc_recv_inject_err; 443192241e0bSTom Erickson #endif 443292241e0bSTom Erickson 44333cb34c60Sahrens /* 44343cb34c60Sahrens * inputs: 44353cb34c60Sahrens * zc_name name of containing filesystem 44363cb34c60Sahrens * zc_nvlist_src{_size} nvlist of properties to apply 44373cb34c60Sahrens * zc_value name of snapshot to create 44383cb34c60Sahrens * zc_string name of clone origin (if DRR_FLAG_CLONE) 44393cb34c60Sahrens * zc_cookie file descriptor to recv from 44403cb34c60Sahrens * zc_begin_record the BEGIN record of the stream (not byteswapped) 44413cb34c60Sahrens * zc_guid force flag 4442c99e4bdcSChris Kirby * zc_cleanup_fd cleanup-on-exit file descriptor 4443c99e4bdcSChris Kirby * zc_action_handle handle for this guid/ds mapping (or zero on first call) 44449c3fd121SMatthew Ahrens * zc_resumable if data is incomplete assume sender will resume 44453cb34c60Sahrens * 44463cb34c60Sahrens * outputs: 44473cb34c60Sahrens * zc_cookie number of bytes read 444892241e0bSTom Erickson * zc_nvlist_dst{_size} error for each unapplied received property 444992241e0bSTom Erickson * zc_obj zprop_errflags_t 4450c99e4bdcSChris Kirby * zc_action_handle handle for this guid/ds mapping 44513cb34c60Sahrens */ 4452fa9e4066Sahrens static int 44533cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc) 4454fa9e4066Sahrens { 4455fa9e4066Sahrens file_t *fp; 44563cb34c60Sahrens dmu_recv_cookie_t drc; 4457f18faf3fSek boolean_t force = (boolean_t)zc->zc_guid; 445892241e0bSTom Erickson int fd; 445992241e0bSTom Erickson int error = 0; 446092241e0bSTom Erickson int props_error = 0; 446192241e0bSTom Erickson nvlist_t *errors; 44623cb34c60Sahrens offset_t off; 446392241e0bSTom Erickson nvlist_t *props = NULL; /* sent properties */ 446492241e0bSTom Erickson nvlist_t *origprops = NULL; /* existing properties */ 44655878fad7SDan McDonald nvlist_t *delayprops = NULL; /* sent properties applied post-receive */ 44663b2aab18SMatthew Ahrens char *origin = NULL; 44673cb34c60Sahrens char *tosnap; 44689adfa60dSMatthew Ahrens char tofs[ZFS_MAX_DATASET_NAME_LEN]; 446992241e0bSTom Erickson boolean_t first_recvd_props = B_FALSE; 4470fa9e4066Sahrens 44713ccfa83cSahrens if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 4472f18faf3fSek strchr(zc->zc_value, '@') == NULL || 4473f18faf3fSek strchr(zc->zc_value, '%')) 4474be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 44753ccfa83cSahrens 44763cb34c60Sahrens (void) strcpy(tofs, zc->zc_value); 44773cb34c60Sahrens tosnap = strchr(tofs, '@'); 447892241e0bSTom Erickson *tosnap++ = '\0'; 44793cb34c60Sahrens 4480dd328bf6SToomas Soome if (zc->zc_nvlist_src != 0 && 44813cb34c60Sahrens (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 4482478ed9adSEric Taylor zc->zc_iflags, &props)) != 0) 44833cb34c60Sahrens return (error); 44843cb34c60Sahrens 4485fa9e4066Sahrens fd = zc->zc_cookie; 4486fa9e4066Sahrens fp = getf(fd); 44873cb34c60Sahrens if (fp == NULL) { 44883cb34c60Sahrens nvlist_free(props); 4489be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 44903cb34c60Sahrens } 4491f18faf3fSek 44929c3fd121SMatthew Ahrens errors = fnvlist_alloc(); 449392241e0bSTom Erickson 44943b2aab18SMatthew Ahrens if (zc->zc_string[0]) 44953b2aab18SMatthew Ahrens origin = zc->zc_string; 44963b2aab18SMatthew Ahrens 44973b2aab18SMatthew Ahrens error = dmu_recv_begin(tofs, tosnap, 44989c3fd121SMatthew Ahrens &zc->zc_begin_record, force, zc->zc_resumable, origin, &drc); 44993b2aab18SMatthew Ahrens if (error != 0) 45003b2aab18SMatthew Ahrens goto out; 45013b2aab18SMatthew Ahrens 45023b2aab18SMatthew Ahrens /* 45033b2aab18SMatthew Ahrens * Set properties before we receive the stream so that they are applied 45043b2aab18SMatthew Ahrens * to the new data. Note that we must call dmu_recv_stream() if 45053b2aab18SMatthew Ahrens * dmu_recv_begin() succeeds. 45063b2aab18SMatthew Ahrens */ 45073b2aab18SMatthew Ahrens if (props != NULL && !drc.drc_newfs) { 45083b2aab18SMatthew Ahrens if (spa_version(dsl_dataset_get_spa(drc.drc_ds)) >= 45093b2aab18SMatthew Ahrens SPA_VERSION_RECVD_PROPS && 45103b2aab18SMatthew Ahrens !dsl_prop_get_hasrecvd(tofs)) 451192241e0bSTom Erickson first_recvd_props = B_TRUE; 451292241e0bSTom Erickson 4513745cd3c5Smaybee /* 451492241e0bSTom Erickson * If new received properties are supplied, they are to 451592241e0bSTom Erickson * completely replace the existing received properties, so stash 451692241e0bSTom Erickson * away the existing ones. 4517745cd3c5Smaybee */ 45183b2aab18SMatthew Ahrens if (dsl_prop_get_received(tofs, &origprops) == 0) { 451992241e0bSTom Erickson nvlist_t *errlist = NULL; 452092241e0bSTom Erickson /* 452192241e0bSTom Erickson * Don't bother writing a property if its value won't 452292241e0bSTom Erickson * change (and avoid the unnecessary security checks). 452392241e0bSTom Erickson * 452492241e0bSTom Erickson * The first receive after SPA_VERSION_RECVD_PROPS is a 452592241e0bSTom Erickson * special case where we blow away all local properties 452692241e0bSTom Erickson * regardless. 452792241e0bSTom Erickson */ 452892241e0bSTom Erickson if (!first_recvd_props) 452992241e0bSTom Erickson props_reduce(props, origprops); 45303b2aab18SMatthew Ahrens if (zfs_check_clearable(tofs, origprops, &errlist) != 0) 453192241e0bSTom Erickson (void) nvlist_merge(errors, errlist, 0); 453292241e0bSTom Erickson nvlist_free(errlist); 45333cb34c60Sahrens 45343b2aab18SMatthew Ahrens if (clear_received_props(tofs, origprops, 45353b2aab18SMatthew Ahrens first_recvd_props ? NULL : props) != 0) 453692241e0bSTom Erickson zc->zc_obj |= ZPROP_ERR_NOCLEAR; 45373b2aab18SMatthew Ahrens } else { 453892241e0bSTom Erickson zc->zc_obj |= ZPROP_ERR_NOCLEAR; 453992241e0bSTom Erickson } 45403b2aab18SMatthew Ahrens } 454192241e0bSTom Erickson 45423b2aab18SMatthew Ahrens if (props != NULL) { 45433b2aab18SMatthew Ahrens props_error = dsl_prop_set_hasrecvd(tofs); 45443b2aab18SMatthew Ahrens 45453b2aab18SMatthew Ahrens if (props_error == 0) { 45465878fad7SDan McDonald delayprops = extract_delay_props(props); 45473b2aab18SMatthew Ahrens (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, 45483b2aab18SMatthew Ahrens props, errors); 45493b2aab18SMatthew Ahrens } 455092241e0bSTom Erickson } 455192241e0bSTom Erickson 45523cb34c60Sahrens off = fp->f_offset; 4553c99e4bdcSChris Kirby error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd, 4554c99e4bdcSChris Kirby &zc->zc_action_handle); 4555a2eea2e1Sahrens 4556f4b94bdeSMatthew Ahrens if (error == 0) { 4557f4b94bdeSMatthew Ahrens zfsvfs_t *zfsvfs = NULL; 4558745cd3c5Smaybee 4559f4b94bdeSMatthew Ahrens if (getzfsvfs(tofs, &zfsvfs) == 0) { 4560f4b94bdeSMatthew Ahrens /* online recv */ 4561690041b9SAndriy Gapon dsl_dataset_t *ds; 4562f4b94bdeSMatthew Ahrens int end_err; 4563745cd3c5Smaybee 4564690041b9SAndriy Gapon ds = dmu_objset_ds(zfsvfs->z_os); 4565503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 4566f4b94bdeSMatthew Ahrens /* 4567f4b94bdeSMatthew Ahrens * If the suspend fails, then the recv_end will 4568f4b94bdeSMatthew Ahrens * likely also fail, and clean up after itself. 4569f4b94bdeSMatthew Ahrens */ 457091948b51SKeith M Wesolowski end_err = dmu_recv_end(&drc, zfsvfs); 45715c703fceSGeorge Wilson if (error == 0) 4572690041b9SAndriy Gapon error = zfs_resume_fs(zfsvfs, ds); 4573f4b94bdeSMatthew Ahrens error = error ? error : end_err; 4574f4b94bdeSMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 4575745cd3c5Smaybee } else { 457691948b51SKeith M Wesolowski error = dmu_recv_end(&drc, NULL); 45773cb34c60Sahrens } 45785878fad7SDan McDonald 45795878fad7SDan McDonald /* Set delayed properties now, after we're done receiving. */ 45805878fad7SDan McDonald if (delayprops != NULL && error == 0) { 45815878fad7SDan McDonald (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, 45825878fad7SDan McDonald delayprops, errors); 45835878fad7SDan McDonald } 45845878fad7SDan McDonald } 45855878fad7SDan McDonald 4586*eb633035STom Caputi if (delayprops != NULL && props != NULL) { 45875878fad7SDan McDonald /* 45885878fad7SDan McDonald * Merge delayed props back in with initial props, in case 45895878fad7SDan McDonald * we're DEBUG and zfs_ioc_recv_inject_err is set (which means 45905878fad7SDan McDonald * we have to make sure clear_received_props() includes 45915878fad7SDan McDonald * the delayed properties). 45925878fad7SDan McDonald * 45935878fad7SDan McDonald * Since zfs_ioc_recv_inject_err is only in DEBUG kernels, 45945878fad7SDan McDonald * using ASSERT() will be just like a VERIFY. 45955878fad7SDan McDonald */ 45965878fad7SDan McDonald ASSERT(nvlist_merge(props, delayprops, 0) == 0); 45975878fad7SDan McDonald nvlist_free(delayprops); 45985878fad7SDan McDonald } 45995878fad7SDan McDonald 46005878fad7SDan McDonald /* 46015878fad7SDan McDonald * Now that all props, initial and delayed, are set, report the prop 46025878fad7SDan McDonald * errors to the caller. 46035878fad7SDan McDonald */ 46045878fad7SDan McDonald if (zc->zc_nvlist_dst_size != 0 && 46055878fad7SDan McDonald (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 || 46065878fad7SDan McDonald put_nvlist(zc, errors) != 0)) { 46075878fad7SDan McDonald /* 46085878fad7SDan McDonald * Caller made zc->zc_nvlist_dst less than the minimum expected 46095878fad7SDan McDonald * size or supplied an invalid address. 46105878fad7SDan McDonald */ 46115878fad7SDan McDonald props_error = SET_ERROR(EINVAL); 461247f263f4Sek } 46133cb34c60Sahrens 46143cb34c60Sahrens zc->zc_cookie = off - fp->f_offset; 46153cb34c60Sahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 46163cb34c60Sahrens fp->f_offset = off; 4617a2eea2e1Sahrens 461892241e0bSTom Erickson #ifdef DEBUG 461992241e0bSTom Erickson if (zfs_ioc_recv_inject_err) { 462092241e0bSTom Erickson zfs_ioc_recv_inject_err = B_FALSE; 462192241e0bSTom Erickson error = 1; 462292241e0bSTom Erickson } 462392241e0bSTom Erickson #endif 4624745cd3c5Smaybee /* 4625745cd3c5Smaybee * On error, restore the original props. 4626745cd3c5Smaybee */ 46273b2aab18SMatthew Ahrens if (error != 0 && props != NULL && !drc.drc_newfs) { 46283b2aab18SMatthew Ahrens if (clear_received_props(tofs, props, NULL) != 0) { 46293b2aab18SMatthew Ahrens /* 46303b2aab18SMatthew Ahrens * We failed to clear the received properties. 46313b2aab18SMatthew Ahrens * Since we may have left a $recvd value on the 46323b2aab18SMatthew Ahrens * system, we can't clear the $hasrecvd flag. 46333b2aab18SMatthew Ahrens */ 463492241e0bSTom Erickson zc->zc_obj |= ZPROP_ERR_NORESTORE; 46353b2aab18SMatthew Ahrens } else if (first_recvd_props) { 46363b2aab18SMatthew Ahrens dsl_prop_unset_hasrecvd(tofs); 463792241e0bSTom Erickson } 463892241e0bSTom Erickson 463992241e0bSTom Erickson if (origprops == NULL && !drc.drc_newfs) { 464092241e0bSTom Erickson /* We failed to stash the original properties. */ 464192241e0bSTom Erickson zc->zc_obj |= ZPROP_ERR_NORESTORE; 464292241e0bSTom Erickson } 464392241e0bSTom Erickson 464492241e0bSTom Erickson /* 464592241e0bSTom Erickson * dsl_props_set() will not convert RECEIVED to LOCAL on or 464692241e0bSTom Erickson * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL 464792241e0bSTom Erickson * explictly if we're restoring local properties cleared in the 464892241e0bSTom Erickson * first new-style receive. 464992241e0bSTom Erickson */ 465092241e0bSTom Erickson if (origprops != NULL && 465192241e0bSTom Erickson zfs_set_prop_nvlist(tofs, (first_recvd_props ? 465292241e0bSTom Erickson ZPROP_SRC_LOCAL : ZPROP_SRC_RECEIVED), 465392241e0bSTom Erickson origprops, NULL) != 0) { 465492241e0bSTom Erickson /* 465592241e0bSTom Erickson * We stashed the original properties but failed to 465692241e0bSTom Erickson * restore them. 465792241e0bSTom Erickson */ 465892241e0bSTom Erickson zc->zc_obj |= ZPROP_ERR_NORESTORE; 465992241e0bSTom Erickson } 4660745cd3c5Smaybee } 4661745cd3c5Smaybee out: 4662745cd3c5Smaybee nvlist_free(props); 4663745cd3c5Smaybee nvlist_free(origprops); 466492241e0bSTom Erickson nvlist_free(errors); 4665fa9e4066Sahrens releasef(fd); 466692241e0bSTom Erickson 466792241e0bSTom Erickson if (error == 0) 466892241e0bSTom Erickson error = props_error; 466992241e0bSTom Erickson 4670fa9e4066Sahrens return (error); 4671fa9e4066Sahrens } 4672fa9e4066Sahrens 46733cb34c60Sahrens /* 46743cb34c60Sahrens * inputs: 46753cb34c60Sahrens * zc_name name of snapshot to send 46763cb34c60Sahrens * zc_cookie file descriptor to send stream to 4677a7f53a56SChris Kirby * zc_obj fromorigin flag (mutually exclusive with zc_fromobj) 4678a7f53a56SChris Kirby * zc_sendobj objsetid of snapshot to send 4679a7f53a56SChris Kirby * zc_fromobj objsetid of incremental fromsnap (may be zero) 468019b94df9SMatthew Ahrens * zc_guid if set, estimate size of stream only. zc_cookie is ignored. 468119b94df9SMatthew Ahrens * output size in zc_objset_type. 4682b5152584SMatthew Ahrens * zc_flags lzc_send_flags 46833cb34c60Sahrens * 468478f17100SMatthew Ahrens * outputs: 468578f17100SMatthew Ahrens * zc_objset_type estimated size, if zc_guid is set 46863cb34c60Sahrens */ 4687fa9e4066Sahrens static int 46883cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc) 4689fa9e4066Sahrens { 4690fa9e4066Sahrens int error; 46913cb34c60Sahrens offset_t off; 469219b94df9SMatthew Ahrens boolean_t estimate = (zc->zc_guid != 0); 46935d7b4d43SMatthew Ahrens boolean_t embedok = (zc->zc_flags & 0x1); 4694b5152584SMatthew Ahrens boolean_t large_block_ok = (zc->zc_flags & 0x2); 46955602294fSDan Kimmel boolean_t compressok = (zc->zc_flags & 0x4); 4696*eb633035STom Caputi boolean_t rawok = (zc->zc_flags & 0x8); 4697fa9e4066Sahrens 46983b2aab18SMatthew Ahrens if (zc->zc_obj != 0) { 46993b2aab18SMatthew Ahrens dsl_pool_t *dp; 47003b2aab18SMatthew Ahrens dsl_dataset_t *tosnap; 4701a7f53a56SChris Kirby 47023b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 47033b2aab18SMatthew Ahrens if (error != 0) 4704a7f53a56SChris Kirby return (error); 47053b2aab18SMatthew Ahrens 47063b2aab18SMatthew Ahrens error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &tosnap); 47073b2aab18SMatthew Ahrens if (error != 0) { 47083b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 4709fa9e4066Sahrens return (error); 4710fa9e4066Sahrens } 47113b2aab18SMatthew Ahrens 47123b2aab18SMatthew Ahrens if (dsl_dir_is_clone(tosnap->ds_dir)) 4713c1379625SJustin T. Gibbs zc->zc_fromobj = 4714c1379625SJustin T. Gibbs dsl_dir_phys(tosnap->ds_dir)->dd_origin_obj; 47153b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 47163b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 47174445fffbSMatthew Ahrens } 47184445fffbSMatthew Ahrens 47193b2aab18SMatthew Ahrens if (estimate) { 47203b2aab18SMatthew Ahrens dsl_pool_t *dp; 47213b2aab18SMatthew Ahrens dsl_dataset_t *tosnap; 47223b2aab18SMatthew Ahrens dsl_dataset_t *fromsnap = NULL; 47234445fffbSMatthew Ahrens 47243b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 47253b2aab18SMatthew Ahrens if (error != 0) 47263b2aab18SMatthew Ahrens return (error); 47273b2aab18SMatthew Ahrens 4728*eb633035STom Caputi error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, 4729*eb633035STom Caputi FTAG, &tosnap); 47303b2aab18SMatthew Ahrens if (error != 0) { 47313b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 47323b2aab18SMatthew Ahrens return (error); 47334445fffbSMatthew Ahrens } 47344445fffbSMatthew Ahrens 47353b2aab18SMatthew Ahrens if (zc->zc_fromobj != 0) { 47363b2aab18SMatthew Ahrens error = dsl_dataset_hold_obj(dp, zc->zc_fromobj, 47373b2aab18SMatthew Ahrens FTAG, &fromsnap); 47383b2aab18SMatthew Ahrens if (error != 0) { 47393b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 47403b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 47414445fffbSMatthew Ahrens return (error); 47424445fffbSMatthew Ahrens } 47434445fffbSMatthew Ahrens } 4744fa9e4066Sahrens 4745*eb633035STom Caputi error = dmu_send_estimate(tosnap, fromsnap, compressok || rawok, 474619b94df9SMatthew Ahrens &zc->zc_objset_type); 47473b2aab18SMatthew Ahrens 47483b2aab18SMatthew Ahrens if (fromsnap != NULL) 47493b2aab18SMatthew Ahrens dsl_dataset_rele(fromsnap, FTAG); 47503b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 47513b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 475219b94df9SMatthew Ahrens } else { 475319b94df9SMatthew Ahrens file_t *fp = getf(zc->zc_cookie); 47543b2aab18SMatthew Ahrens if (fp == NULL) 4755be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 4756fa9e4066Sahrens 475719b94df9SMatthew Ahrens off = fp->f_offset; 47583b2aab18SMatthew Ahrens error = dmu_send_obj(zc->zc_name, zc->zc_sendobj, 4759*eb633035STom Caputi zc->zc_fromobj, embedok, large_block_ok, compressok, rawok, 4760b5152584SMatthew Ahrens zc->zc_cookie, fp->f_vnode, &off); 4761fa9e4066Sahrens 476219b94df9SMatthew Ahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 476319b94df9SMatthew Ahrens fp->f_offset = off; 476419b94df9SMatthew Ahrens releasef(zc->zc_cookie); 476519b94df9SMatthew Ahrens } 4766fa9e4066Sahrens return (error); 4767fa9e4066Sahrens } 4768fa9e4066Sahrens 47694e3c9f44SBill Pijewski /* 47704e3c9f44SBill Pijewski * inputs: 47714e3c9f44SBill Pijewski * zc_name name of snapshot on which to report progress 47724e3c9f44SBill Pijewski * zc_cookie file descriptor of send stream 47734e3c9f44SBill Pijewski * 47744e3c9f44SBill Pijewski * outputs: 47754e3c9f44SBill Pijewski * zc_cookie number of bytes written in send stream thus far 47764e3c9f44SBill Pijewski */ 47774e3c9f44SBill Pijewski static int 47784e3c9f44SBill Pijewski zfs_ioc_send_progress(zfs_cmd_t *zc) 47794e3c9f44SBill Pijewski { 47803b2aab18SMatthew Ahrens dsl_pool_t *dp; 47814e3c9f44SBill Pijewski dsl_dataset_t *ds; 47824e3c9f44SBill Pijewski dmu_sendarg_t *dsp = NULL; 47834e3c9f44SBill Pijewski int error; 47844e3c9f44SBill Pijewski 47853b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 47863b2aab18SMatthew Ahrens if (error != 0) 47873b2aab18SMatthew Ahrens return (error); 47883b2aab18SMatthew Ahrens 47893b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds); 47903b2aab18SMatthew Ahrens if (error != 0) { 47913b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 47924e3c9f44SBill Pijewski return (error); 47933b2aab18SMatthew Ahrens } 47944e3c9f44SBill Pijewski 47954e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 47964e3c9f44SBill Pijewski 47974e3c9f44SBill Pijewski /* 47984e3c9f44SBill Pijewski * Iterate over all the send streams currently active on this dataset. 47994e3c9f44SBill Pijewski * If there's one which matches the specified file descriptor _and_ the 48004e3c9f44SBill Pijewski * stream was started by the current process, return the progress of 48014e3c9f44SBill Pijewski * that stream. 48024e3c9f44SBill Pijewski */ 48034e3c9f44SBill Pijewski for (dsp = list_head(&ds->ds_sendstreams); dsp != NULL; 48044e3c9f44SBill Pijewski dsp = list_next(&ds->ds_sendstreams, dsp)) { 48054e3c9f44SBill Pijewski if (dsp->dsa_outfd == zc->zc_cookie && 48064e3c9f44SBill Pijewski dsp->dsa_proc == curproc) 48074e3c9f44SBill Pijewski break; 48084e3c9f44SBill Pijewski } 48094e3c9f44SBill Pijewski 48104e3c9f44SBill Pijewski if (dsp != NULL) 48114e3c9f44SBill Pijewski zc->zc_cookie = *(dsp->dsa_off); 48124e3c9f44SBill Pijewski else 4813be6fd75aSMatthew Ahrens error = SET_ERROR(ENOENT); 48144e3c9f44SBill Pijewski 48154e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 48164e3c9f44SBill Pijewski dsl_dataset_rele(ds, FTAG); 48173b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 48184e3c9f44SBill Pijewski return (error); 48194e3c9f44SBill Pijewski } 48204e3c9f44SBill Pijewski 4821ea8dc4b6Seschrock static int 4822ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc) 4823ea8dc4b6Seschrock { 4824ea8dc4b6Seschrock int id, error; 4825ea8dc4b6Seschrock 4826ea8dc4b6Seschrock error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 4827ea8dc4b6Seschrock &zc->zc_inject_record); 4828ea8dc4b6Seschrock 4829ea8dc4b6Seschrock if (error == 0) 4830ea8dc4b6Seschrock zc->zc_guid = (uint64_t)id; 4831ea8dc4b6Seschrock 4832ea8dc4b6Seschrock return (error); 4833ea8dc4b6Seschrock } 4834ea8dc4b6Seschrock 4835ea8dc4b6Seschrock static int 4836ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc) 4837ea8dc4b6Seschrock { 4838ea8dc4b6Seschrock return (zio_clear_fault((int)zc->zc_guid)); 4839ea8dc4b6Seschrock } 4840ea8dc4b6Seschrock 4841ea8dc4b6Seschrock static int 4842ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc) 4843ea8dc4b6Seschrock { 4844ea8dc4b6Seschrock int id = (int)zc->zc_guid; 4845ea8dc4b6Seschrock int error; 4846ea8dc4b6Seschrock 4847ea8dc4b6Seschrock error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 4848ea8dc4b6Seschrock &zc->zc_inject_record); 4849ea8dc4b6Seschrock 4850ea8dc4b6Seschrock zc->zc_guid = id; 4851ea8dc4b6Seschrock 4852ea8dc4b6Seschrock return (error); 4853ea8dc4b6Seschrock } 4854ea8dc4b6Seschrock 4855ea8dc4b6Seschrock static int 4856ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc) 4857ea8dc4b6Seschrock { 4858ea8dc4b6Seschrock spa_t *spa; 4859ea8dc4b6Seschrock int error; 4860e9dbad6fSeschrock size_t count = (size_t)zc->zc_nvlist_dst_size; 4861ea8dc4b6Seschrock 4862ea8dc4b6Seschrock if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 4863ea8dc4b6Seschrock return (error); 4864ea8dc4b6Seschrock 4865e9dbad6fSeschrock error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 4866ea8dc4b6Seschrock &count); 4867ea8dc4b6Seschrock if (error == 0) 4868e9dbad6fSeschrock zc->zc_nvlist_dst_size = count; 4869ea8dc4b6Seschrock else 4870e9dbad6fSeschrock zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 4871ea8dc4b6Seschrock 4872ea8dc4b6Seschrock spa_close(spa, FTAG); 4873ea8dc4b6Seschrock 4874ea8dc4b6Seschrock return (error); 4875ea8dc4b6Seschrock } 4876ea8dc4b6Seschrock 4877ea8dc4b6Seschrock static int 4878ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc) 4879ea8dc4b6Seschrock { 4880ea8dc4b6Seschrock spa_t *spa; 4881ea8dc4b6Seschrock vdev_t *vd; 4882bb8b5132Sek int error; 4883ea8dc4b6Seschrock 4884b87f3af3Sperrin /* 4885b87f3af3Sperrin * On zpool clear we also fix up missing slogs 4886b87f3af3Sperrin */ 4887b87f3af3Sperrin mutex_enter(&spa_namespace_lock); 4888b87f3af3Sperrin spa = spa_lookup(zc->zc_name); 4889b87f3af3Sperrin if (spa == NULL) { 4890b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 4891be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 4892b87f3af3Sperrin } 4893b24ab676SJeff Bonwick if (spa_get_log_state(spa) == SPA_LOG_MISSING) { 4894b87f3af3Sperrin /* we need to let spa_open/spa_load clear the chains */ 4895b24ab676SJeff Bonwick spa_set_log_state(spa, SPA_LOG_CLEAR); 4896b87f3af3Sperrin } 4897468c413aSTim Haley spa->spa_last_open_failed = 0; 4898b87f3af3Sperrin mutex_exit(&spa_namespace_lock); 4899b87f3af3Sperrin 4900c8ee1847SVictor Latushkin if (zc->zc_cookie & ZPOOL_NO_REWIND) { 4901468c413aSTim Haley error = spa_open(zc->zc_name, &spa, FTAG); 4902468c413aSTim Haley } else { 4903468c413aSTim Haley nvlist_t *policy; 4904468c413aSTim Haley nvlist_t *config = NULL; 4905468c413aSTim Haley 4906dd328bf6SToomas Soome if (zc->zc_nvlist_src == 0) 4907be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 4908468c413aSTim Haley 4909468c413aSTim Haley if ((error = get_nvlist(zc->zc_nvlist_src, 4910468c413aSTim Haley zc->zc_nvlist_src_size, zc->zc_iflags, &policy)) == 0) { 4911468c413aSTim Haley error = spa_open_rewind(zc->zc_name, &spa, FTAG, 4912468c413aSTim Haley policy, &config); 4913468c413aSTim Haley if (config != NULL) { 49144b964adaSGeorge Wilson int err; 49154b964adaSGeorge Wilson 49164b964adaSGeorge Wilson if ((err = put_nvlist(zc, config)) != 0) 49174b964adaSGeorge Wilson error = err; 4918468c413aSTim Haley nvlist_free(config); 4919468c413aSTim Haley } 4920468c413aSTim Haley nvlist_free(policy); 4921468c413aSTim Haley } 4922468c413aSTim Haley } 4923468c413aSTim Haley 49243b2aab18SMatthew Ahrens if (error != 0) 4925ea8dc4b6Seschrock return (error); 4926ea8dc4b6Seschrock 4927e0f1c0afSOlaf Faaland /* 4928e0f1c0afSOlaf Faaland * If multihost is enabled, resuming I/O is unsafe as another 4929e0f1c0afSOlaf Faaland * host may have imported the pool. 4930e0f1c0afSOlaf Faaland */ 4931e0f1c0afSOlaf Faaland if (spa_multihost(spa) && spa_suspended(spa)) 4932e0f1c0afSOlaf Faaland return (SET_ERROR(EINVAL)); 4933e0f1c0afSOlaf Faaland 49348f18d1faSGeorge Wilson spa_vdev_state_enter(spa, SCL_NONE); 4935ea8dc4b6Seschrock 4936e9dbad6fSeschrock if (zc->zc_guid == 0) { 4937ea8dc4b6Seschrock vd = NULL; 4938c5904d13Seschrock } else { 4939c5904d13Seschrock vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE); 4940fa94a07fSbrendan if (vd == NULL) { 4941e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, ENODEV); 4942fa94a07fSbrendan spa_close(spa, FTAG); 4943be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 4944fa94a07fSbrendan } 4945ea8dc4b6Seschrock } 4946ea8dc4b6Seschrock 4947e14bb325SJeff Bonwick vdev_clear(spa, vd); 4948e14bb325SJeff Bonwick 4949e14bb325SJeff Bonwick (void) spa_vdev_state_exit(spa, NULL, 0); 4950ea8dc4b6Seschrock 4951e14bb325SJeff Bonwick /* 4952e14bb325SJeff Bonwick * Resume any suspended I/Os. 4953e14bb325SJeff Bonwick */ 495454d692b7SGeorge Wilson if (zio_resume(spa) != 0) 4955be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 4956ea8dc4b6Seschrock 4957ea8dc4b6Seschrock spa_close(spa, FTAG); 4958ea8dc4b6Seschrock 495954d692b7SGeorge Wilson return (error); 4960ea8dc4b6Seschrock } 4961ea8dc4b6Seschrock 49624263d13fSGeorge Wilson static int 49634263d13fSGeorge Wilson zfs_ioc_pool_reopen(zfs_cmd_t *zc) 49644263d13fSGeorge Wilson { 49654263d13fSGeorge Wilson spa_t *spa; 49664263d13fSGeorge Wilson int error; 49674263d13fSGeorge Wilson 49684263d13fSGeorge Wilson error = spa_open(zc->zc_name, &spa, FTAG); 49693b2aab18SMatthew Ahrens if (error != 0) 49704263d13fSGeorge Wilson return (error); 49714263d13fSGeorge Wilson 49724263d13fSGeorge Wilson spa_vdev_state_enter(spa, SCL_NONE); 4973d6afdce2SGeorge Wilson 4974d6afdce2SGeorge Wilson /* 4975d6afdce2SGeorge Wilson * If a resilver is already in progress then set the 4976d6afdce2SGeorge Wilson * spa_scrub_reopen flag to B_TRUE so that we don't restart 4977d6afdce2SGeorge Wilson * the scan as a side effect of the reopen. Otherwise, let 4978d6afdce2SGeorge Wilson * vdev_open() decided if a resilver is required. 4979d6afdce2SGeorge Wilson */ 4980d6afdce2SGeorge Wilson spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool); 49814263d13fSGeorge Wilson vdev_reopen(spa->spa_root_vdev); 4982d6afdce2SGeorge Wilson spa->spa_scrub_reopen = B_FALSE; 4983d6afdce2SGeorge Wilson 49844263d13fSGeorge Wilson (void) spa_vdev_state_exit(spa, NULL, 0); 49854263d13fSGeorge Wilson spa_close(spa, FTAG); 49864263d13fSGeorge Wilson return (0); 49874263d13fSGeorge Wilson } 49883cb34c60Sahrens /* 49893cb34c60Sahrens * inputs: 49903cb34c60Sahrens * zc_name name of filesystem 49913cb34c60Sahrens * 4992681d9761SEric Taylor * outputs: 4993681d9761SEric Taylor * zc_string name of conflicting snapshot, if there is one 49943cb34c60Sahrens */ 499599653d4eSeschrock static int 499699653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc) 499799653d4eSeschrock { 4998a4b8c9aaSAndrew Stormont dsl_pool_t *dp; 4999a4b8c9aaSAndrew Stormont dsl_dataset_t *ds, *ods; 5000a4b8c9aaSAndrew Stormont char origin[ZFS_MAX_DATASET_NAME_LEN]; 50010b69c2f0Sahrens char *cp; 5002a4b8c9aaSAndrew Stormont int error; 5003a4b8c9aaSAndrew Stormont 5004add927f8Sloli zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 5005add927f8Sloli if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 || 5006add927f8Sloli strchr(zc->zc_name, '%')) 5007add927f8Sloli return (SET_ERROR(EINVAL)); 5008add927f8Sloli 5009a4b8c9aaSAndrew Stormont error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 5010a4b8c9aaSAndrew Stormont if (error != 0) 5011a4b8c9aaSAndrew Stormont return (error); 5012a4b8c9aaSAndrew Stormont 5013a4b8c9aaSAndrew Stormont error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds); 5014a4b8c9aaSAndrew Stormont if (error != 0) { 5015a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 5016a4b8c9aaSAndrew Stormont return (error); 5017a4b8c9aaSAndrew Stormont } 5018a4b8c9aaSAndrew Stormont 5019a4b8c9aaSAndrew Stormont if (!dsl_dir_is_clone(ds->ds_dir)) { 5020a4b8c9aaSAndrew Stormont dsl_dataset_rele(ds, FTAG); 5021a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 5022a4b8c9aaSAndrew Stormont return (SET_ERROR(EINVAL)); 5023a4b8c9aaSAndrew Stormont } 5024a4b8c9aaSAndrew Stormont 5025a4b8c9aaSAndrew Stormont error = dsl_dataset_hold_obj(dp, 5026a4b8c9aaSAndrew Stormont dsl_dir_phys(ds->ds_dir)->dd_origin_obj, FTAG, &ods); 5027a4b8c9aaSAndrew Stormont if (error != 0) { 5028a4b8c9aaSAndrew Stormont dsl_dataset_rele(ds, FTAG); 5029a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 5030a4b8c9aaSAndrew Stormont return (error); 5031a4b8c9aaSAndrew Stormont } 5032a4b8c9aaSAndrew Stormont 5033a4b8c9aaSAndrew Stormont dsl_dataset_name(ods, origin); 5034a4b8c9aaSAndrew Stormont dsl_dataset_rele(ods, FTAG); 5035a4b8c9aaSAndrew Stormont dsl_dataset_rele(ds, FTAG); 5036a4b8c9aaSAndrew Stormont dsl_pool_rele(dp, FTAG); 50370b69c2f0Sahrens 50380b69c2f0Sahrens /* 50390b69c2f0Sahrens * We don't need to unmount *all* the origin fs's snapshots, but 50400b69c2f0Sahrens * it's easier. 50410b69c2f0Sahrens */ 5042a4b8c9aaSAndrew Stormont cp = strchr(origin, '@'); 50430b69c2f0Sahrens if (cp) 50440b69c2f0Sahrens *cp = '\0'; 5045a4b8c9aaSAndrew Stormont (void) dmu_objset_find(origin, 50463b2aab18SMatthew Ahrens zfs_unmount_snap_cb, NULL, DS_FIND_SNAPSHOTS); 5047681d9761SEric Taylor return (dsl_dataset_promote(zc->zc_name, zc->zc_string)); 504899653d4eSeschrock } 504999653d4eSeschrock 505014843421SMatthew Ahrens /* 505114843421SMatthew Ahrens * Retrieve a single {user|group}{used|quota}@... property. 505214843421SMatthew Ahrens * 505314843421SMatthew Ahrens * inputs: 505414843421SMatthew Ahrens * zc_name name of filesystem 505514843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 505614843421SMatthew Ahrens * zc_value domain name (eg. "S-1-234-567-89") 505714843421SMatthew Ahrens * zc_guid RID/UID/GID 505814843421SMatthew Ahrens * 505914843421SMatthew Ahrens * outputs: 506014843421SMatthew Ahrens * zc_cookie property value 506114843421SMatthew Ahrens */ 506214843421SMatthew Ahrens static int 506314843421SMatthew Ahrens zfs_ioc_userspace_one(zfs_cmd_t *zc) 506414843421SMatthew Ahrens { 506514843421SMatthew Ahrens zfsvfs_t *zfsvfs; 506614843421SMatthew Ahrens int error; 506714843421SMatthew Ahrens 506814843421SMatthew Ahrens if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS) 5069be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 507014843421SMatthew Ahrens 50711412a1a2SMark Shellenbaum error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 50723b2aab18SMatthew Ahrens if (error != 0) 507314843421SMatthew Ahrens return (error); 507414843421SMatthew Ahrens 507514843421SMatthew Ahrens error = zfs_userspace_one(zfsvfs, 507614843421SMatthew Ahrens zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie); 507714843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 507814843421SMatthew Ahrens 507914843421SMatthew Ahrens return (error); 508014843421SMatthew Ahrens } 508114843421SMatthew Ahrens 508214843421SMatthew Ahrens /* 508314843421SMatthew Ahrens * inputs: 508414843421SMatthew Ahrens * zc_name name of filesystem 508514843421SMatthew Ahrens * zc_cookie zap cursor 508614843421SMatthew Ahrens * zc_objset_type zfs_userquota_prop_t 508714843421SMatthew Ahrens * zc_nvlist_dst[_size] buffer to fill (not really an nvlist) 508814843421SMatthew Ahrens * 508914843421SMatthew Ahrens * outputs: 509014843421SMatthew Ahrens * zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t) 509114843421SMatthew Ahrens * zc_cookie zap cursor 509214843421SMatthew Ahrens */ 509314843421SMatthew Ahrens static int 509414843421SMatthew Ahrens zfs_ioc_userspace_many(zfs_cmd_t *zc) 509514843421SMatthew Ahrens { 509614843421SMatthew Ahrens zfsvfs_t *zfsvfs; 5097eeb85002STim Haley int bufsize = zc->zc_nvlist_dst_size; 509814843421SMatthew Ahrens 5099eeb85002STim Haley if (bufsize <= 0) 5100be6fd75aSMatthew Ahrens return (SET_ERROR(ENOMEM)); 5101eeb85002STim Haley 51021412a1a2SMark Shellenbaum int error = zfsvfs_hold(zc->zc_name, FTAG, &zfsvfs, B_FALSE); 51033b2aab18SMatthew Ahrens if (error != 0) 510414843421SMatthew Ahrens return (error); 510514843421SMatthew Ahrens 510614843421SMatthew Ahrens void *buf = kmem_alloc(bufsize, KM_SLEEP); 510714843421SMatthew Ahrens 510814843421SMatthew Ahrens error = zfs_userspace_many(zfsvfs, zc->zc_objset_type, &zc->zc_cookie, 510914843421SMatthew Ahrens buf, &zc->zc_nvlist_dst_size); 511014843421SMatthew Ahrens 511114843421SMatthew Ahrens if (error == 0) { 511214843421SMatthew Ahrens error = xcopyout(buf, 511314843421SMatthew Ahrens (void *)(uintptr_t)zc->zc_nvlist_dst, 511414843421SMatthew Ahrens zc->zc_nvlist_dst_size); 511514843421SMatthew Ahrens } 511614843421SMatthew Ahrens kmem_free(buf, bufsize); 511714843421SMatthew Ahrens zfsvfs_rele(zfsvfs, FTAG); 511814843421SMatthew Ahrens 511914843421SMatthew Ahrens return (error); 512014843421SMatthew Ahrens } 512114843421SMatthew Ahrens 512214843421SMatthew Ahrens /* 512314843421SMatthew Ahrens * inputs: 512414843421SMatthew Ahrens * zc_name name of filesystem 512514843421SMatthew Ahrens * 512614843421SMatthew Ahrens * outputs: 512714843421SMatthew Ahrens * none 512814843421SMatthew Ahrens */ 512914843421SMatthew Ahrens static int 513014843421SMatthew Ahrens zfs_ioc_userspace_upgrade(zfs_cmd_t *zc) 513114843421SMatthew Ahrens { 513214843421SMatthew Ahrens objset_t *os; 51331195e687SMark J Musante int error = 0; 513414843421SMatthew Ahrens zfsvfs_t *zfsvfs; 513514843421SMatthew Ahrens 513614843421SMatthew Ahrens if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { 5137503ad85cSMatthew Ahrens if (!dmu_objset_userused_enabled(zfsvfs->z_os)) { 513814843421SMatthew Ahrens /* 513914843421SMatthew Ahrens * If userused is not enabled, it may be because the 514014843421SMatthew Ahrens * objset needs to be closed & reopened (to grow the 514114843421SMatthew Ahrens * objset_phys_t). Suspend/resume the fs will do that. 514214843421SMatthew Ahrens */ 51435f5913bbSAndriy Gapon dsl_dataset_t *ds, *newds; 5144690041b9SAndriy Gapon 5145690041b9SAndriy Gapon ds = dmu_objset_ds(zfsvfs->z_os); 5146503ad85cSMatthew Ahrens error = zfs_suspend_fs(zfsvfs); 514791948b51SKeith M Wesolowski if (error == 0) { 51485f5913bbSAndriy Gapon dmu_objset_refresh_ownership(ds, &newds, 5149*eb633035STom Caputi B_TRUE, zfsvfs); 51505f5913bbSAndriy Gapon error = zfs_resume_fs(zfsvfs, newds); 515191948b51SKeith M Wesolowski } 515214843421SMatthew Ahrens } 515314843421SMatthew Ahrens if (error == 0) 515414843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(zfsvfs->z_os); 515514843421SMatthew Ahrens VFS_RELE(zfsvfs->z_vfs); 515614843421SMatthew Ahrens } else { 5157503ad85cSMatthew Ahrens /* XXX kind of reading contents without owning */ 5158*eb633035STom Caputi error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, FTAG, &os); 51593b2aab18SMatthew Ahrens if (error != 0) 516014843421SMatthew Ahrens return (error); 516114843421SMatthew Ahrens 516214843421SMatthew Ahrens error = dmu_objset_userspace_upgrade(os); 5163*eb633035STom Caputi dmu_objset_rele_flags(os, B_TRUE, FTAG); 516414843421SMatthew Ahrens } 516514843421SMatthew Ahrens 516614843421SMatthew Ahrens return (error); 516714843421SMatthew Ahrens } 516814843421SMatthew Ahrens 5169ecd6cf80Smarks /* 5170ecd6cf80Smarks * We don't want to have a hard dependency 5171ecd6cf80Smarks * against some special symbols in sharefs 5172da6c28aaSamw * nfs, and smbsrv. Determine them if needed when 5173ecd6cf80Smarks * the first file system is shared. 5174da6c28aaSamw * Neither sharefs, nfs or smbsrv are unloadable modules. 5175ecd6cf80Smarks */ 5176da6c28aaSamw int (*znfsexport_fs)(void *arg); 5177ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); 5178da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share); 5179da6c28aaSamw 5180da6c28aaSamw int zfs_nfsshare_inited; 5181da6c28aaSamw int zfs_smbshare_inited; 5182ecd6cf80Smarks 5183ecd6cf80Smarks ddi_modhandle_t nfs_mod; 5184ecd6cf80Smarks ddi_modhandle_t sharefs_mod; 5185da6c28aaSamw ddi_modhandle_t smbsrv_mod; 5186ecd6cf80Smarks kmutex_t zfs_share_lock; 5187ecd6cf80Smarks 5188da6c28aaSamw static int 5189da6c28aaSamw zfs_init_sharefs() 5190da6c28aaSamw { 5191da6c28aaSamw int error; 5192da6c28aaSamw 5193da6c28aaSamw ASSERT(MUTEX_HELD(&zfs_share_lock)); 5194da6c28aaSamw /* Both NFS and SMB shares also require sharetab support. */ 5195da6c28aaSamw if (sharefs_mod == NULL && ((sharefs_mod = 5196da6c28aaSamw ddi_modopen("fs/sharefs", 5197da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 5198be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5199da6c28aaSamw } 5200da6c28aaSamw if (zshare_fs == NULL && ((zshare_fs = 5201da6c28aaSamw (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) 5202da6c28aaSamw ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { 5203be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5204da6c28aaSamw } 5205da6c28aaSamw return (0); 5206da6c28aaSamw } 5207da6c28aaSamw 5208ecd6cf80Smarks static int 5209ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc) 5210ecd6cf80Smarks { 5211ecd6cf80Smarks int error; 5212ecd6cf80Smarks int opcode; 5213ecd6cf80Smarks 5214da6c28aaSamw switch (zc->zc_share.z_sharetype) { 5215da6c28aaSamw case ZFS_SHARE_NFS: 5216da6c28aaSamw case ZFS_UNSHARE_NFS: 5217da6c28aaSamw if (zfs_nfsshare_inited == 0) { 5218da6c28aaSamw mutex_enter(&zfs_share_lock); 5219da6c28aaSamw if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", 5220da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 5221da6c28aaSamw mutex_exit(&zfs_share_lock); 5222be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5223da6c28aaSamw } 5224da6c28aaSamw if (znfsexport_fs == NULL && 5225da6c28aaSamw ((znfsexport_fs = (int (*)(void *)) 5226da6c28aaSamw ddi_modsym(nfs_mod, 5227da6c28aaSamw "nfs_export", &error)) == NULL)) { 5228da6c28aaSamw mutex_exit(&zfs_share_lock); 5229be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5230da6c28aaSamw } 5231da6c28aaSamw error = zfs_init_sharefs(); 52323b2aab18SMatthew Ahrens if (error != 0) { 5233da6c28aaSamw mutex_exit(&zfs_share_lock); 5234be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5235da6c28aaSamw } 5236da6c28aaSamw zfs_nfsshare_inited = 1; 5237ecd6cf80Smarks mutex_exit(&zfs_share_lock); 5238ecd6cf80Smarks } 5239da6c28aaSamw break; 5240da6c28aaSamw case ZFS_SHARE_SMB: 5241da6c28aaSamw case ZFS_UNSHARE_SMB: 5242da6c28aaSamw if (zfs_smbshare_inited == 0) { 5243da6c28aaSamw mutex_enter(&zfs_share_lock); 5244da6c28aaSamw if (smbsrv_mod == NULL && ((smbsrv_mod = 5245da6c28aaSamw ddi_modopen("drv/smbsrv", 5246da6c28aaSamw KRTLD_MODE_FIRST, &error)) == NULL)) { 5247da6c28aaSamw mutex_exit(&zfs_share_lock); 5248be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5249da6c28aaSamw } 5250da6c28aaSamw if (zsmbexport_fs == NULL && ((zsmbexport_fs = 5251da6c28aaSamw (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, 5252faa1795aSjb "smb_server_share", &error)) == NULL)) { 5253da6c28aaSamw mutex_exit(&zfs_share_lock); 5254be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5255da6c28aaSamw } 5256da6c28aaSamw error = zfs_init_sharefs(); 52573b2aab18SMatthew Ahrens if (error != 0) { 5258da6c28aaSamw mutex_exit(&zfs_share_lock); 5259be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 5260da6c28aaSamw } 5261da6c28aaSamw zfs_smbshare_inited = 1; 5262ecd6cf80Smarks mutex_exit(&zfs_share_lock); 5263ecd6cf80Smarks } 5264da6c28aaSamw break; 5265da6c28aaSamw default: 5266be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5267da6c28aaSamw } 5268ecd6cf80Smarks 5269da6c28aaSamw switch (zc->zc_share.z_sharetype) { 5270da6c28aaSamw case ZFS_SHARE_NFS: 5271da6c28aaSamw case ZFS_UNSHARE_NFS: 5272da6c28aaSamw if (error = 5273da6c28aaSamw znfsexport_fs((void *) 5274da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata)) 5275da6c28aaSamw return (error); 5276da6c28aaSamw break; 5277da6c28aaSamw case ZFS_SHARE_SMB: 5278da6c28aaSamw case ZFS_UNSHARE_SMB: 5279da6c28aaSamw if (error = zsmbexport_fs((void *) 5280da6c28aaSamw (uintptr_t)zc->zc_share.z_exportdata, 5281da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? 5282743a77edSAlan Wright B_TRUE: B_FALSE)) { 5283da6c28aaSamw return (error); 5284ecd6cf80Smarks } 5285da6c28aaSamw break; 5286ecd6cf80Smarks } 5287ecd6cf80Smarks 5288da6c28aaSamw opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || 5289da6c28aaSamw zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? 5290ecd6cf80Smarks SHAREFS_ADD : SHAREFS_REMOVE; 5291ecd6cf80Smarks 5292da6c28aaSamw /* 5293da6c28aaSamw * Add or remove share from sharetab 5294da6c28aaSamw */ 5295ecd6cf80Smarks error = zshare_fs(opcode, 5296ecd6cf80Smarks (void *)(uintptr_t)zc->zc_share.z_sharedata, 5297ecd6cf80Smarks zc->zc_share.z_sharemax); 5298ecd6cf80Smarks 5299ecd6cf80Smarks return (error); 5300ecd6cf80Smarks 5301ecd6cf80Smarks } 5302ecd6cf80Smarks 5303743a77edSAlan Wright ace_t full_access[] = { 5304743a77edSAlan Wright {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0} 5305743a77edSAlan Wright }; 5306743a77edSAlan Wright 530799d5e173STim Haley /* 530899d5e173STim Haley * inputs: 530999d5e173STim Haley * zc_name name of containing filesystem 531099d5e173STim Haley * zc_obj object # beyond which we want next in-use object # 531199d5e173STim Haley * 531299d5e173STim Haley * outputs: 531399d5e173STim Haley * zc_obj next in-use object # 531499d5e173STim Haley */ 531599d5e173STim Haley static int 531699d5e173STim Haley zfs_ioc_next_obj(zfs_cmd_t *zc) 531799d5e173STim Haley { 531899d5e173STim Haley objset_t *os = NULL; 531999d5e173STim Haley int error; 532099d5e173STim Haley 5321*eb633035STom Caputi error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, FTAG, &os); 53223b2aab18SMatthew Ahrens if (error != 0) 532399d5e173STim Haley return (error); 532499d5e173STim Haley 532599d5e173STim Haley error = dmu_object_next(os, &zc->zc_obj, B_FALSE, 5326c1379625SJustin T. Gibbs dsl_dataset_phys(os->os_dsl_dataset)->ds_prev_snap_txg); 532799d5e173STim Haley 532899d5e173STim Haley dmu_objset_rele(os, FTAG); 532999d5e173STim Haley return (error); 533099d5e173STim Haley } 533199d5e173STim Haley 533299d5e173STim Haley /* 533399d5e173STim Haley * inputs: 533499d5e173STim Haley * zc_name name of filesystem 533599d5e173STim Haley * zc_value prefix name for snapshot 533699d5e173STim Haley * zc_cleanup_fd cleanup-on-exit file descriptor for calling process 533799d5e173STim Haley * 533899d5e173STim Haley * outputs: 53394445fffbSMatthew Ahrens * zc_value short name of new snapshot 534099d5e173STim Haley */ 534199d5e173STim Haley static int 534299d5e173STim Haley zfs_ioc_tmp_snapshot(zfs_cmd_t *zc) 534399d5e173STim Haley { 534499d5e173STim Haley char *snap_name; 53453b2aab18SMatthew Ahrens char *hold_name; 534699d5e173STim Haley int error; 53473b2aab18SMatthew Ahrens minor_t minor; 534899d5e173STim Haley 53493b2aab18SMatthew Ahrens error = zfs_onexit_fd_hold(zc->zc_cleanup_fd, &minor); 53503b2aab18SMatthew Ahrens if (error != 0) 535199d5e173STim Haley return (error); 535299d5e173STim Haley 53533b2aab18SMatthew Ahrens snap_name = kmem_asprintf("%s-%016llx", zc->zc_value, 53543b2aab18SMatthew Ahrens (u_longlong_t)ddi_get_lbolt64()); 53553b2aab18SMatthew Ahrens hold_name = kmem_asprintf("%%%s", zc->zc_value); 53563b2aab18SMatthew Ahrens 53573b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_tmp(zc->zc_name, snap_name, minor, 53583b2aab18SMatthew Ahrens hold_name); 53593b2aab18SMatthew Ahrens if (error == 0) 53603b2aab18SMatthew Ahrens (void) strcpy(zc->zc_value, snap_name); 536199d5e173STim Haley strfree(snap_name); 53623b2aab18SMatthew Ahrens strfree(hold_name); 53633b2aab18SMatthew Ahrens zfs_onexit_fd_rele(zc->zc_cleanup_fd); 53643b2aab18SMatthew Ahrens return (error); 536599d5e173STim Haley } 536699d5e173STim Haley 536799d5e173STim Haley /* 536899d5e173STim Haley * inputs: 536999d5e173STim Haley * zc_name name of "to" snapshot 537099d5e173STim Haley * zc_value name of "from" snapshot 537199d5e173STim Haley * zc_cookie file descriptor to write diff data on 537299d5e173STim Haley * 537399d5e173STim Haley * outputs: 537499d5e173STim Haley * dmu_diff_record_t's to the file descriptor 537599d5e173STim Haley */ 537699d5e173STim Haley static int 537799d5e173STim Haley zfs_ioc_diff(zfs_cmd_t *zc) 537899d5e173STim Haley { 537999d5e173STim Haley file_t *fp; 538099d5e173STim Haley offset_t off; 538199d5e173STim Haley int error; 538299d5e173STim Haley 538399d5e173STim Haley fp = getf(zc->zc_cookie); 53843b2aab18SMatthew Ahrens if (fp == NULL) 5385be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 538699d5e173STim Haley 538799d5e173STim Haley off = fp->f_offset; 538899d5e173STim Haley 53893b2aab18SMatthew Ahrens error = dmu_diff(zc->zc_name, zc->zc_value, fp->f_vnode, &off); 539099d5e173STim Haley 539199d5e173STim Haley if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 539299d5e173STim Haley fp->f_offset = off; 539399d5e173STim Haley releasef(zc->zc_cookie); 539499d5e173STim Haley 539599d5e173STim Haley return (error); 539699d5e173STim Haley } 539799d5e173STim Haley 5398743a77edSAlan Wright /* 5399743a77edSAlan Wright * Remove all ACL files in shares dir 5400743a77edSAlan Wright */ 5401743a77edSAlan Wright static int 5402743a77edSAlan Wright zfs_smb_acl_purge(znode_t *dzp) 5403743a77edSAlan Wright { 5404743a77edSAlan Wright zap_cursor_t zc; 5405743a77edSAlan Wright zap_attribute_t zap; 5406743a77edSAlan Wright zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 5407743a77edSAlan Wright int error; 5408743a77edSAlan Wright 5409743a77edSAlan Wright for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id); 5410743a77edSAlan Wright (error = zap_cursor_retrieve(&zc, &zap)) == 0; 5411743a77edSAlan Wright zap_cursor_advance(&zc)) { 5412743a77edSAlan Wright if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred, 5413743a77edSAlan Wright NULL, 0)) != 0) 5414743a77edSAlan Wright break; 5415743a77edSAlan Wright } 5416743a77edSAlan Wright zap_cursor_fini(&zc); 5417743a77edSAlan Wright return (error); 5418743a77edSAlan Wright } 5419743a77edSAlan Wright 5420743a77edSAlan Wright static int 5421743a77edSAlan Wright zfs_ioc_smb_acl(zfs_cmd_t *zc) 5422743a77edSAlan Wright { 5423743a77edSAlan Wright vnode_t *vp; 5424743a77edSAlan Wright znode_t *dzp; 5425743a77edSAlan Wright vnode_t *resourcevp = NULL; 5426743a77edSAlan Wright znode_t *sharedir; 5427743a77edSAlan Wright zfsvfs_t *zfsvfs; 5428743a77edSAlan Wright nvlist_t *nvlist; 5429743a77edSAlan Wright char *src, *target; 5430743a77edSAlan Wright vattr_t vattr; 5431743a77edSAlan Wright vsecattr_t vsec; 5432743a77edSAlan Wright int error = 0; 5433743a77edSAlan Wright 5434743a77edSAlan Wright if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, 5435743a77edSAlan Wright NO_FOLLOW, NULL, &vp)) != 0) 5436743a77edSAlan Wright return (error); 5437743a77edSAlan Wright 5438743a77edSAlan Wright /* Now make sure mntpnt and dataset are ZFS */ 5439743a77edSAlan Wright 5440743a77edSAlan Wright if (vp->v_vfsp->vfs_fstype != zfsfstype || 5441743a77edSAlan Wright (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), 5442743a77edSAlan Wright zc->zc_name) != 0)) { 5443743a77edSAlan Wright VN_RELE(vp); 5444be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5445743a77edSAlan Wright } 5446743a77edSAlan Wright 5447743a77edSAlan Wright dzp = VTOZ(vp); 5448743a77edSAlan Wright zfsvfs = dzp->z_zfsvfs; 5449743a77edSAlan Wright ZFS_ENTER(zfsvfs); 5450743a77edSAlan Wright 54519e1320c0SMark Shellenbaum /* 54529e1320c0SMark Shellenbaum * Create share dir if its missing. 54539e1320c0SMark Shellenbaum */ 54549e1320c0SMark Shellenbaum mutex_enter(&zfsvfs->z_lock); 54559e1320c0SMark Shellenbaum if (zfsvfs->z_shares_dir == 0) { 54569e1320c0SMark Shellenbaum dmu_tx_t *tx; 54579e1320c0SMark Shellenbaum 54589e1320c0SMark Shellenbaum tx = dmu_tx_create(zfsvfs->z_os); 54599e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE, 54609e1320c0SMark Shellenbaum ZFS_SHARES_DIR); 54619e1320c0SMark Shellenbaum dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 54629e1320c0SMark Shellenbaum error = dmu_tx_assign(tx, TXG_WAIT); 54633b2aab18SMatthew Ahrens if (error != 0) { 54649e1320c0SMark Shellenbaum dmu_tx_abort(tx); 54659e1320c0SMark Shellenbaum } else { 54669e1320c0SMark Shellenbaum error = zfs_create_share_dir(zfsvfs, tx); 54679e1320c0SMark Shellenbaum dmu_tx_commit(tx); 54689e1320c0SMark Shellenbaum } 54693b2aab18SMatthew Ahrens if (error != 0) { 54709e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 54719e1320c0SMark Shellenbaum VN_RELE(vp); 54729e1320c0SMark Shellenbaum ZFS_EXIT(zfsvfs); 54739e1320c0SMark Shellenbaum return (error); 54749e1320c0SMark Shellenbaum } 54759e1320c0SMark Shellenbaum } 54769e1320c0SMark Shellenbaum mutex_exit(&zfsvfs->z_lock); 54779e1320c0SMark Shellenbaum 54789e1320c0SMark Shellenbaum ASSERT(zfsvfs->z_shares_dir); 5479743a77edSAlan Wright if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &sharedir)) != 0) { 54809e1320c0SMark Shellenbaum VN_RELE(vp); 5481743a77edSAlan Wright ZFS_EXIT(zfsvfs); 5482743a77edSAlan Wright return (error); 5483743a77edSAlan Wright } 5484743a77edSAlan Wright 5485743a77edSAlan Wright switch (zc->zc_cookie) { 5486743a77edSAlan Wright case ZFS_SMB_ACL_ADD: 5487743a77edSAlan Wright vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE; 5488743a77edSAlan Wright vattr.va_type = VREG; 5489743a77edSAlan Wright vattr.va_mode = S_IFREG|0777; 5490743a77edSAlan Wright vattr.va_uid = 0; 5491743a77edSAlan Wright vattr.va_gid = 0; 5492743a77edSAlan Wright 5493743a77edSAlan Wright vsec.vsa_mask = VSA_ACE; 5494743a77edSAlan Wright vsec.vsa_aclentp = &full_access; 5495743a77edSAlan Wright vsec.vsa_aclentsz = sizeof (full_access); 5496743a77edSAlan Wright vsec.vsa_aclcnt = 1; 5497743a77edSAlan Wright 5498743a77edSAlan Wright error = VOP_CREATE(ZTOV(sharedir), zc->zc_string, 5499743a77edSAlan Wright &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec); 5500743a77edSAlan Wright if (resourcevp) 5501743a77edSAlan Wright VN_RELE(resourcevp); 5502743a77edSAlan Wright break; 5503743a77edSAlan Wright 5504743a77edSAlan Wright case ZFS_SMB_ACL_REMOVE: 5505743a77edSAlan Wright error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred, 5506743a77edSAlan Wright NULL, 0); 5507743a77edSAlan Wright break; 5508743a77edSAlan Wright 5509743a77edSAlan Wright case ZFS_SMB_ACL_RENAME: 5510743a77edSAlan Wright if ((error = get_nvlist(zc->zc_nvlist_src, 5511478ed9adSEric Taylor zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) { 5512743a77edSAlan Wright VN_RELE(vp); 55138f5190a5SDan McDonald VN_RELE(ZTOV(sharedir)); 5514743a77edSAlan Wright ZFS_EXIT(zfsvfs); 5515743a77edSAlan Wright return (error); 5516743a77edSAlan Wright } 5517743a77edSAlan Wright if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) || 5518743a77edSAlan Wright nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET, 5519743a77edSAlan Wright &target)) { 5520743a77edSAlan Wright VN_RELE(vp); 552189459e17SMark Shellenbaum VN_RELE(ZTOV(sharedir)); 5522743a77edSAlan Wright ZFS_EXIT(zfsvfs); 55231195e687SMark J Musante nvlist_free(nvlist); 5524743a77edSAlan Wright return (error); 5525743a77edSAlan Wright } 5526743a77edSAlan Wright error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target, 5527743a77edSAlan Wright kcred, NULL, 0); 5528743a77edSAlan Wright nvlist_free(nvlist); 5529743a77edSAlan Wright break; 5530743a77edSAlan Wright 5531743a77edSAlan Wright case ZFS_SMB_ACL_PURGE: 5532743a77edSAlan Wright error = zfs_smb_acl_purge(sharedir); 5533743a77edSAlan Wright break; 5534743a77edSAlan Wright 5535743a77edSAlan Wright default: 5536be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 5537743a77edSAlan Wright break; 5538743a77edSAlan Wright } 5539743a77edSAlan Wright 5540743a77edSAlan Wright VN_RELE(vp); 5541743a77edSAlan Wright VN_RELE(ZTOV(sharedir)); 5542743a77edSAlan Wright 5543743a77edSAlan Wright ZFS_EXIT(zfsvfs); 5544743a77edSAlan Wright 5545743a77edSAlan Wright return (error); 5546743a77edSAlan Wright } 5547743a77edSAlan Wright 5548842727c2SChris Kirby /* 55493b2aab18SMatthew Ahrens * innvl: { 55503b2aab18SMatthew Ahrens * "holds" -> { snapname -> holdname (string), ... } 55513b2aab18SMatthew Ahrens * (optional) "cleanup_fd" -> fd (int32) 55523b2aab18SMatthew Ahrens * } 5553842727c2SChris Kirby * 55543b2aab18SMatthew Ahrens * outnvl: { 55553b2aab18SMatthew Ahrens * snapname -> error value (int32) 55563b2aab18SMatthew Ahrens * ... 55573b2aab18SMatthew Ahrens * } 5558842727c2SChris Kirby */ 55593b2aab18SMatthew Ahrens /* ARGSUSED */ 5560842727c2SChris Kirby static int 55613b2aab18SMatthew Ahrens zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist) 5562842727c2SChris Kirby { 5563752fd8daSJosef 'Jeff' Sipek nvpair_t *pair; 55643b2aab18SMatthew Ahrens nvlist_t *holds; 55653b2aab18SMatthew Ahrens int cleanup_fd = -1; 5566a7f53a56SChris Kirby int error; 5567a7f53a56SChris Kirby minor_t minor = 0; 5568842727c2SChris Kirby 55693b2aab18SMatthew Ahrens error = nvlist_lookup_nvlist(args, "holds", &holds); 55703b2aab18SMatthew Ahrens if (error != 0) 5571be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5572a7f53a56SChris Kirby 5573752fd8daSJosef 'Jeff' Sipek /* make sure the user didn't pass us any invalid (empty) tags */ 5574752fd8daSJosef 'Jeff' Sipek for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; 5575752fd8daSJosef 'Jeff' Sipek pair = nvlist_next_nvpair(holds, pair)) { 5576752fd8daSJosef 'Jeff' Sipek char *htag; 5577752fd8daSJosef 'Jeff' Sipek 5578752fd8daSJosef 'Jeff' Sipek error = nvpair_value_string(pair, &htag); 5579752fd8daSJosef 'Jeff' Sipek if (error != 0) 5580752fd8daSJosef 'Jeff' Sipek return (SET_ERROR(error)); 5581752fd8daSJosef 'Jeff' Sipek 5582752fd8daSJosef 'Jeff' Sipek if (strlen(htag) == 0) 5583752fd8daSJosef 'Jeff' Sipek return (SET_ERROR(EINVAL)); 5584752fd8daSJosef 'Jeff' Sipek } 5585752fd8daSJosef 'Jeff' Sipek 55863b2aab18SMatthew Ahrens if (nvlist_lookup_int32(args, "cleanup_fd", &cleanup_fd) == 0) { 55873b2aab18SMatthew Ahrens error = zfs_onexit_fd_hold(cleanup_fd, &minor); 55883b2aab18SMatthew Ahrens if (error != 0) 5589a7f53a56SChris Kirby return (error); 5590a7f53a56SChris Kirby } 5591a7f53a56SChris Kirby 55923b2aab18SMatthew Ahrens error = dsl_dataset_user_hold(holds, minor, errlist); 55933b2aab18SMatthew Ahrens if (minor != 0) 55943b2aab18SMatthew Ahrens zfs_onexit_fd_rele(cleanup_fd); 5595a7f53a56SChris Kirby return (error); 5596842727c2SChris Kirby } 5597842727c2SChris Kirby 5598842727c2SChris Kirby /* 55993b2aab18SMatthew Ahrens * innvl is not used. 5600842727c2SChris Kirby * 56013b2aab18SMatthew Ahrens * outnvl: { 56023b2aab18SMatthew Ahrens * holdname -> time added (uint64 seconds since epoch) 56033b2aab18SMatthew Ahrens * ... 56043b2aab18SMatthew Ahrens * } 5605842727c2SChris Kirby */ 56063b2aab18SMatthew Ahrens /* ARGSUSED */ 5607842727c2SChris Kirby static int 56083b2aab18SMatthew Ahrens zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl) 5609842727c2SChris Kirby { 56109c2acf00SAlek Pinchuk ASSERT3P(args, ==, NULL); 56113b2aab18SMatthew Ahrens return (dsl_dataset_get_holds(snapname, outnvl)); 5612842727c2SChris Kirby } 5613842727c2SChris Kirby 5614842727c2SChris Kirby /* 56153b2aab18SMatthew Ahrens * innvl: { 56163b2aab18SMatthew Ahrens * snapname -> { holdname, ... } 56173b2aab18SMatthew Ahrens * ... 56183b2aab18SMatthew Ahrens * } 5619842727c2SChris Kirby * 56203b2aab18SMatthew Ahrens * outnvl: { 56213b2aab18SMatthew Ahrens * snapname -> error value (int32) 56223b2aab18SMatthew Ahrens * ... 56233b2aab18SMatthew Ahrens * } 5624842727c2SChris Kirby */ 56253b2aab18SMatthew Ahrens /* ARGSUSED */ 5626842727c2SChris Kirby static int 56273b2aab18SMatthew Ahrens zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist) 5628842727c2SChris Kirby { 56293b2aab18SMatthew Ahrens return (dsl_dataset_user_release(holds, errlist)); 5630842727c2SChris Kirby } 5631842727c2SChris Kirby 563219b94df9SMatthew Ahrens /* 563319b94df9SMatthew Ahrens * inputs: 563419b94df9SMatthew Ahrens * zc_name name of new filesystem or snapshot 563519b94df9SMatthew Ahrens * zc_value full name of old snapshot 563619b94df9SMatthew Ahrens * 563719b94df9SMatthew Ahrens * outputs: 563819b94df9SMatthew Ahrens * zc_cookie space in bytes 563919b94df9SMatthew Ahrens * zc_objset_type compressed space in bytes 564019b94df9SMatthew Ahrens * zc_perm_action uncompressed space in bytes 564119b94df9SMatthew Ahrens */ 564219b94df9SMatthew Ahrens static int 564319b94df9SMatthew Ahrens zfs_ioc_space_written(zfs_cmd_t *zc) 564419b94df9SMatthew Ahrens { 564519b94df9SMatthew Ahrens int error; 56463b2aab18SMatthew Ahrens dsl_pool_t *dp; 564719b94df9SMatthew Ahrens dsl_dataset_t *new, *old; 564819b94df9SMatthew Ahrens 56493b2aab18SMatthew Ahrens error = dsl_pool_hold(zc->zc_name, FTAG, &dp); 565019b94df9SMatthew Ahrens if (error != 0) 565119b94df9SMatthew Ahrens return (error); 56523b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &new); 56533b2aab18SMatthew Ahrens if (error != 0) { 56543b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 56553b2aab18SMatthew Ahrens return (error); 56563b2aab18SMatthew Ahrens } 56573b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, zc->zc_value, FTAG, &old); 565819b94df9SMatthew Ahrens if (error != 0) { 565919b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 56603b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 566119b94df9SMatthew Ahrens return (error); 566219b94df9SMatthew Ahrens } 566319b94df9SMatthew Ahrens 566419b94df9SMatthew Ahrens error = dsl_dataset_space_written(old, new, &zc->zc_cookie, 566519b94df9SMatthew Ahrens &zc->zc_objset_type, &zc->zc_perm_action); 566619b94df9SMatthew Ahrens dsl_dataset_rele(old, FTAG); 566719b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 56683b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 566919b94df9SMatthew Ahrens return (error); 567019b94df9SMatthew Ahrens } 56713b2aab18SMatthew Ahrens 567219b94df9SMatthew Ahrens /* 56734445fffbSMatthew Ahrens * innvl: { 56744445fffbSMatthew Ahrens * "firstsnap" -> snapshot name 56754445fffbSMatthew Ahrens * } 567619b94df9SMatthew Ahrens * 56774445fffbSMatthew Ahrens * outnvl: { 56784445fffbSMatthew Ahrens * "used" -> space in bytes 56794445fffbSMatthew Ahrens * "compressed" -> compressed space in bytes 56804445fffbSMatthew Ahrens * "uncompressed" -> uncompressed space in bytes 56814445fffbSMatthew Ahrens * } 568219b94df9SMatthew Ahrens */ 568319b94df9SMatthew Ahrens static int 56844445fffbSMatthew Ahrens zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl) 568519b94df9SMatthew Ahrens { 568619b94df9SMatthew Ahrens int error; 56873b2aab18SMatthew Ahrens dsl_pool_t *dp; 568819b94df9SMatthew Ahrens dsl_dataset_t *new, *old; 56894445fffbSMatthew Ahrens char *firstsnap; 56904445fffbSMatthew Ahrens uint64_t used, comp, uncomp; 569119b94df9SMatthew Ahrens 56924445fffbSMatthew Ahrens if (nvlist_lookup_string(innvl, "firstsnap", &firstsnap) != 0) 5693be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 56944445fffbSMatthew Ahrens 56953b2aab18SMatthew Ahrens error = dsl_pool_hold(lastsnap, FTAG, &dp); 569619b94df9SMatthew Ahrens if (error != 0) 569719b94df9SMatthew Ahrens return (error); 56983b2aab18SMatthew Ahrens 56993b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, lastsnap, FTAG, &new); 570024218bebSAndriy Gapon if (error == 0 && !new->ds_is_snapshot) { 570124218bebSAndriy Gapon dsl_dataset_rele(new, FTAG); 570224218bebSAndriy Gapon error = SET_ERROR(EINVAL); 570324218bebSAndriy Gapon } 57043b2aab18SMatthew Ahrens if (error != 0) { 57053b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 57063b2aab18SMatthew Ahrens return (error); 57073b2aab18SMatthew Ahrens } 57083b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, firstsnap, FTAG, &old); 570924218bebSAndriy Gapon if (error == 0 && !old->ds_is_snapshot) { 571024218bebSAndriy Gapon dsl_dataset_rele(old, FTAG); 571124218bebSAndriy Gapon error = SET_ERROR(EINVAL); 571224218bebSAndriy Gapon } 571319b94df9SMatthew Ahrens if (error != 0) { 571419b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 57153b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 571619b94df9SMatthew Ahrens return (error); 571719b94df9SMatthew Ahrens } 571819b94df9SMatthew Ahrens 57194445fffbSMatthew Ahrens error = dsl_dataset_space_wouldfree(old, new, &used, &comp, &uncomp); 572019b94df9SMatthew Ahrens dsl_dataset_rele(old, FTAG); 572119b94df9SMatthew Ahrens dsl_dataset_rele(new, FTAG); 57223b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 57234445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "used", used); 57244445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "compressed", comp); 57254445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "uncompressed", uncomp); 572619b94df9SMatthew Ahrens return (error); 572719b94df9SMatthew Ahrens } 572819b94df9SMatthew Ahrens 5729ecd6cf80Smarks /* 57304445fffbSMatthew Ahrens * innvl: { 57314445fffbSMatthew Ahrens * "fd" -> file descriptor to write stream to (int32) 57324445fffbSMatthew Ahrens * (optional) "fromsnap" -> full snap name to send an incremental from 5733b5152584SMatthew Ahrens * (optional) "largeblockok" -> (value ignored) 5734b5152584SMatthew Ahrens * indicates that blocks > 128KB are permitted 57355d7b4d43SMatthew Ahrens * (optional) "embedok" -> (value ignored) 57365d7b4d43SMatthew Ahrens * presence indicates DRR_WRITE_EMBEDDED records are permitted 57375602294fSDan Kimmel * (optional) "compressok" -> (value ignored) 57385602294fSDan Kimmel * presence indicates compressed DRR_WRITE records are permitted 5739*eb633035STom Caputi * (optional) "rawok" -> (value ignored) 5740*eb633035STom Caputi * presence indicates raw encrypted records should be used. 57419c3fd121SMatthew Ahrens * (optional) "resume_object" and "resume_offset" -> (uint64) 57429c3fd121SMatthew Ahrens * if present, resume send stream from specified object and offset. 57434445fffbSMatthew Ahrens * } 57444445fffbSMatthew Ahrens * 57454445fffbSMatthew Ahrens * outnvl is unused 5746ecd6cf80Smarks */ 57474445fffbSMatthew Ahrens /* ARGSUSED */ 57484445fffbSMatthew Ahrens static int 57494445fffbSMatthew Ahrens zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) 57504445fffbSMatthew Ahrens { 57514445fffbSMatthew Ahrens int error; 57524445fffbSMatthew Ahrens offset_t off; 57533b2aab18SMatthew Ahrens char *fromname = NULL; 57544445fffbSMatthew Ahrens int fd; 5755b5152584SMatthew Ahrens boolean_t largeblockok; 57565d7b4d43SMatthew Ahrens boolean_t embedok; 57575602294fSDan Kimmel boolean_t compressok; 5758*eb633035STom Caputi boolean_t rawok; 57599c3fd121SMatthew Ahrens uint64_t resumeobj = 0; 57609c3fd121SMatthew Ahrens uint64_t resumeoff = 0; 57614445fffbSMatthew Ahrens 57624445fffbSMatthew Ahrens error = nvlist_lookup_int32(innvl, "fd", &fd); 57634445fffbSMatthew Ahrens if (error != 0) 5764be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 57654445fffbSMatthew Ahrens 57663b2aab18SMatthew Ahrens (void) nvlist_lookup_string(innvl, "fromsnap", &fromname); 57674445fffbSMatthew Ahrens 5768b5152584SMatthew Ahrens largeblockok = nvlist_exists(innvl, "largeblockok"); 57695d7b4d43SMatthew Ahrens embedok = nvlist_exists(innvl, "embedok"); 57705602294fSDan Kimmel compressok = nvlist_exists(innvl, "compressok"); 5771*eb633035STom Caputi rawok = nvlist_exists(innvl, "rawok"); 57725d7b4d43SMatthew Ahrens 57739c3fd121SMatthew Ahrens (void) nvlist_lookup_uint64(innvl, "resume_object", &resumeobj); 57749c3fd121SMatthew Ahrens (void) nvlist_lookup_uint64(innvl, "resume_offset", &resumeoff); 57759c3fd121SMatthew Ahrens 57764445fffbSMatthew Ahrens file_t *fp = getf(fd); 57773b2aab18SMatthew Ahrens if (fp == NULL) 5778be6fd75aSMatthew Ahrens return (SET_ERROR(EBADF)); 57794445fffbSMatthew Ahrens 57804445fffbSMatthew Ahrens off = fp->f_offset; 57815602294fSDan Kimmel error = dmu_send(snapname, fromname, embedok, largeblockok, compressok, 5782*eb633035STom Caputi rawok, fd, resumeobj, resumeoff, fp->f_vnode, &off); 57834445fffbSMatthew Ahrens 57844445fffbSMatthew Ahrens if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) 57854445fffbSMatthew Ahrens fp->f_offset = off; 57864445fffbSMatthew Ahrens releasef(fd); 57874445fffbSMatthew Ahrens return (error); 57884445fffbSMatthew Ahrens } 57894445fffbSMatthew Ahrens 57904445fffbSMatthew Ahrens /* 57914445fffbSMatthew Ahrens * Determine approximately how large a zfs send stream will be -- the number 57924445fffbSMatthew Ahrens * of bytes that will be written to the fd supplied to zfs_ioc_send_new(). 57934445fffbSMatthew Ahrens * 57944445fffbSMatthew Ahrens * innvl: { 5795643da460SMax Grossman * (optional) "from" -> full snap or bookmark name to send an incremental 5796643da460SMax Grossman * from 57975602294fSDan Kimmel * (optional) "largeblockok" -> (value ignored) 57985602294fSDan Kimmel * indicates that blocks > 128KB are permitted 57995602294fSDan Kimmel * (optional) "embedok" -> (value ignored) 58005602294fSDan Kimmel * presence indicates DRR_WRITE_EMBEDDED records are permitted 58015602294fSDan Kimmel * (optional) "compressok" -> (value ignored) 58025602294fSDan Kimmel * presence indicates compressed DRR_WRITE records are permitted 58034445fffbSMatthew Ahrens * } 58044445fffbSMatthew Ahrens * 58054445fffbSMatthew Ahrens * outnvl: { 58064445fffbSMatthew Ahrens * "space" -> bytes of space (uint64) 58074445fffbSMatthew Ahrens * } 58084445fffbSMatthew Ahrens */ 58094445fffbSMatthew Ahrens static int 58104445fffbSMatthew Ahrens zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) 58114445fffbSMatthew Ahrens { 58123b2aab18SMatthew Ahrens dsl_pool_t *dp; 58133b2aab18SMatthew Ahrens dsl_dataset_t *tosnap; 58144445fffbSMatthew Ahrens int error; 58154445fffbSMatthew Ahrens char *fromname; 58165602294fSDan Kimmel boolean_t compressok; 5817*eb633035STom Caputi boolean_t rawok; 58184445fffbSMatthew Ahrens uint64_t space; 58194445fffbSMatthew Ahrens 58203b2aab18SMatthew Ahrens error = dsl_pool_hold(snapname, FTAG, &dp); 58213b2aab18SMatthew Ahrens if (error != 0) 58223b2aab18SMatthew Ahrens return (error); 58233b2aab18SMatthew Ahrens 58243b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, snapname, FTAG, &tosnap); 58253b2aab18SMatthew Ahrens if (error != 0) { 58263b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 58274445fffbSMatthew Ahrens return (error); 58283b2aab18SMatthew Ahrens } 58294445fffbSMatthew Ahrens 58305602294fSDan Kimmel compressok = nvlist_exists(innvl, "compressok"); 5831*eb633035STom Caputi rawok = nvlist_exists(innvl, "rawok"); 58325602294fSDan Kimmel 5833643da460SMax Grossman error = nvlist_lookup_string(innvl, "from", &fromname); 58344445fffbSMatthew Ahrens if (error == 0) { 5835643da460SMax Grossman if (strchr(fromname, '@') != NULL) { 5836643da460SMax Grossman /* 5837643da460SMax Grossman * If from is a snapshot, hold it and use the more 5838643da460SMax Grossman * efficient dmu_send_estimate to estimate send space 5839643da460SMax Grossman * size using deadlists. 5840643da460SMax Grossman */ 5841643da460SMax Grossman dsl_dataset_t *fromsnap; 5842643da460SMax Grossman error = dsl_dataset_hold(dp, fromname, FTAG, &fromsnap); 5843643da460SMax Grossman if (error != 0) 5844643da460SMax Grossman goto out; 5845*eb633035STom Caputi error = dmu_send_estimate(tosnap, fromsnap, 5846*eb633035STom Caputi compressok || rawok, &space); 5847643da460SMax Grossman dsl_dataset_rele(fromsnap, FTAG); 5848643da460SMax Grossman } else if (strchr(fromname, '#') != NULL) { 5849643da460SMax Grossman /* 5850643da460SMax Grossman * If from is a bookmark, fetch the creation TXG of the 5851643da460SMax Grossman * snapshot it was created from and use that to find 5852643da460SMax Grossman * blocks that were born after it. 5853643da460SMax Grossman */ 5854643da460SMax Grossman zfs_bookmark_phys_t frombm; 5855643da460SMax Grossman 5856643da460SMax Grossman error = dsl_bookmark_lookup(dp, fromname, tosnap, 5857643da460SMax Grossman &frombm); 5858643da460SMax Grossman if (error != 0) 5859643da460SMax Grossman goto out; 5860643da460SMax Grossman error = dmu_send_estimate_from_txg(tosnap, 5861*eb633035STom Caputi frombm.zbm_creation_txg, compressok || rawok, 5862*eb633035STom Caputi &space); 5863643da460SMax Grossman } else { 5864643da460SMax Grossman /* 5865643da460SMax Grossman * from is not properly formatted as a snapshot or 5866643da460SMax Grossman * bookmark 5867643da460SMax Grossman */ 5868643da460SMax Grossman error = SET_ERROR(EINVAL); 5869643da460SMax Grossman goto out; 58704445fffbSMatthew Ahrens } 5871643da460SMax Grossman } else { 5872b852c2f5SToomas Soome /* 5873b852c2f5SToomas Soome * If estimating the size of a full send, use dmu_send_estimate. 5874b852c2f5SToomas Soome */ 5875*eb633035STom Caputi error = dmu_send_estimate(tosnap, NULL, compressok || rawok, 5876*eb633035STom Caputi &space); 58774445fffbSMatthew Ahrens } 58784445fffbSMatthew Ahrens 58794445fffbSMatthew Ahrens fnvlist_add_uint64(outnvl, "space", space); 58804445fffbSMatthew Ahrens 5881643da460SMax Grossman out: 58823b2aab18SMatthew Ahrens dsl_dataset_rele(tosnap, FTAG); 58833b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 58844445fffbSMatthew Ahrens return (error); 58854445fffbSMatthew Ahrens } 58864445fffbSMatthew Ahrens 58879c2acf00SAlek Pinchuk /* 58889c2acf00SAlek Pinchuk * Sync the currently open TXG to disk for the specified pool. 58899c2acf00SAlek Pinchuk * This is somewhat similar to 'zfs_sync()'. 58909c2acf00SAlek Pinchuk * For cases that do not result in error this ioctl will wait for 58919c2acf00SAlek Pinchuk * the currently open TXG to commit before returning back to the caller. 58929c2acf00SAlek Pinchuk * 58939c2acf00SAlek Pinchuk * innvl: { 58949c2acf00SAlek Pinchuk * "force" -> when true, force uberblock update even if there is no dirty data. 58959c2acf00SAlek Pinchuk * In addition this will cause the vdev configuration to be written 58969c2acf00SAlek Pinchuk * out including updating the zpool cache file. (boolean_t) 58979c2acf00SAlek Pinchuk * } 58989c2acf00SAlek Pinchuk * 58999c2acf00SAlek Pinchuk * onvl is unused 59009c2acf00SAlek Pinchuk */ 59019c2acf00SAlek Pinchuk /* ARGSUSED */ 59029c2acf00SAlek Pinchuk static int 59039c2acf00SAlek Pinchuk zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl) 59049c2acf00SAlek Pinchuk { 59059c2acf00SAlek Pinchuk int err; 59069c2acf00SAlek Pinchuk boolean_t force; 59079c2acf00SAlek Pinchuk spa_t *spa; 59089c2acf00SAlek Pinchuk 59099c2acf00SAlek Pinchuk if ((err = spa_open(pool, &spa, FTAG)) != 0) 59109c2acf00SAlek Pinchuk return (err); 59119c2acf00SAlek Pinchuk 59129c2acf00SAlek Pinchuk force = fnvlist_lookup_boolean_value(innvl, "force"); 59139c2acf00SAlek Pinchuk if (force) { 59149c2acf00SAlek Pinchuk spa_config_enter(spa, SCL_CONFIG, FTAG, RW_WRITER); 59159c2acf00SAlek Pinchuk vdev_config_dirty(spa->spa_root_vdev); 59169c2acf00SAlek Pinchuk spa_config_exit(spa, SCL_CONFIG, FTAG); 59179c2acf00SAlek Pinchuk } 59189c2acf00SAlek Pinchuk txg_wait_synced(spa_get_dsl(spa), 0); 59199c2acf00SAlek Pinchuk 59209c2acf00SAlek Pinchuk spa_close(spa, FTAG); 59219c2acf00SAlek Pinchuk 59229c2acf00SAlek Pinchuk return (err); 59239c2acf00SAlek Pinchuk } 59249c2acf00SAlek Pinchuk 5925*eb633035STom Caputi /* 5926*eb633035STom Caputi * Load a user's wrapping key into the kernel. 5927*eb633035STom Caputi * innvl: { 5928*eb633035STom Caputi * "hidden_args" -> { "wkeydata" -> value } 5929*eb633035STom Caputi * raw uint8_t array of encryption wrapping key data (32 bytes) 5930*eb633035STom Caputi * (optional) "noop" -> (value ignored) 5931*eb633035STom Caputi * presence indicated key should only be verified, not loaded 5932*eb633035STom Caputi * } 5933*eb633035STom Caputi */ 5934*eb633035STom Caputi /* ARGSUSED */ 5935*eb633035STom Caputi static int 5936*eb633035STom Caputi zfs_ioc_load_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl) 5937*eb633035STom Caputi { 5938*eb633035STom Caputi int ret = 0; 5939*eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 5940*eb633035STom Caputi nvlist_t *hidden_args; 5941*eb633035STom Caputi boolean_t noop = nvlist_exists(innvl, "noop"); 5942*eb633035STom Caputi 5943*eb633035STom Caputi if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) { 5944*eb633035STom Caputi ret = SET_ERROR(EINVAL); 5945*eb633035STom Caputi goto error; 5946*eb633035STom Caputi } 5947*eb633035STom Caputi 5948*eb633035STom Caputi ret = nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args); 5949*eb633035STom Caputi if (ret != 0) { 5950*eb633035STom Caputi ret = SET_ERROR(EINVAL); 5951*eb633035STom Caputi goto error; 5952*eb633035STom Caputi } 5953*eb633035STom Caputi 5954*eb633035STom Caputi ret = dsl_crypto_params_create_nvlist(DCP_CMD_NONE, NULL, 5955*eb633035STom Caputi hidden_args, &dcp); 5956*eb633035STom Caputi if (ret != 0) 5957*eb633035STom Caputi goto error; 5958*eb633035STom Caputi 5959*eb633035STom Caputi ret = spa_keystore_load_wkey(dsname, dcp, noop); 5960*eb633035STom Caputi if (ret != 0) 5961*eb633035STom Caputi goto error; 5962*eb633035STom Caputi 5963*eb633035STom Caputi dsl_crypto_params_free(dcp, noop); 5964*eb633035STom Caputi 5965*eb633035STom Caputi return (0); 5966*eb633035STom Caputi 5967*eb633035STom Caputi error: 5968*eb633035STom Caputi dsl_crypto_params_free(dcp, B_TRUE); 5969*eb633035STom Caputi return (ret); 5970*eb633035STom Caputi } 5971*eb633035STom Caputi 5972*eb633035STom Caputi /* 5973*eb633035STom Caputi * Unload a user's wrapping key from the kernel. 5974*eb633035STom Caputi * Both innvl and outnvl are unused. 5975*eb633035STom Caputi */ 5976*eb633035STom Caputi /* ARGSUSED */ 5977*eb633035STom Caputi static int 5978*eb633035STom Caputi zfs_ioc_unload_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl) 5979*eb633035STom Caputi { 5980*eb633035STom Caputi int ret = 0; 5981*eb633035STom Caputi 5982*eb633035STom Caputi if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) { 5983*eb633035STom Caputi ret = (SET_ERROR(EINVAL)); 5984*eb633035STom Caputi goto out; 5985*eb633035STom Caputi } 5986*eb633035STom Caputi 5987*eb633035STom Caputi ret = spa_keystore_unload_wkey(dsname); 5988*eb633035STom Caputi if (ret != 0) 5989*eb633035STom Caputi goto out; 5990*eb633035STom Caputi 5991*eb633035STom Caputi out: 5992*eb633035STom Caputi return (ret); 5993*eb633035STom Caputi } 5994*eb633035STom Caputi 5995*eb633035STom Caputi /* 5996*eb633035STom Caputi * Changes a user's wrapping key used to decrypt a dataset. The keyformat, 5997*eb633035STom Caputi * keylocation, pbkdf2salt, and pbkdf2iters properties can also be specified 5998*eb633035STom Caputi * here to change how the key is derived in userspace. 5999*eb633035STom Caputi * 6000*eb633035STom Caputi * innvl: { 6001*eb633035STom Caputi * "hidden_args" (optional) -> { "wkeydata" -> value } 6002*eb633035STom Caputi * raw uint8_t array of new encryption wrapping key data (32 bytes) 6003*eb633035STom Caputi * "props" (optional) -> { prop -> value } 6004*eb633035STom Caputi * } 6005*eb633035STom Caputi * 6006*eb633035STom Caputi * outnvl is unused 6007*eb633035STom Caputi */ 6008*eb633035STom Caputi /* ARGSUSED */ 6009*eb633035STom Caputi static int 6010*eb633035STom Caputi zfs_ioc_change_key(const char *dsname, nvlist_t *innvl, nvlist_t *outnvl) 6011*eb633035STom Caputi { 6012*eb633035STom Caputi int ret; 6013*eb633035STom Caputi uint64_t cmd = DCP_CMD_NONE; 6014*eb633035STom Caputi dsl_crypto_params_t *dcp = NULL; 6015*eb633035STom Caputi nvlist_t *args = NULL, *hidden_args = NULL; 6016*eb633035STom Caputi 6017*eb633035STom Caputi if (strchr(dsname, '@') != NULL || strchr(dsname, '%') != NULL) { 6018*eb633035STom Caputi ret = (SET_ERROR(EINVAL)); 6019*eb633035STom Caputi goto error; 6020*eb633035STom Caputi } 6021*eb633035STom Caputi 6022*eb633035STom Caputi (void) nvlist_lookup_uint64(innvl, "crypt_cmd", &cmd); 6023*eb633035STom Caputi (void) nvlist_lookup_nvlist(innvl, "props", &args); 6024*eb633035STom Caputi (void) nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args); 6025*eb633035STom Caputi 6026*eb633035STom Caputi ret = dsl_crypto_params_create_nvlist(cmd, args, hidden_args, &dcp); 6027*eb633035STom Caputi if (ret != 0) 6028*eb633035STom Caputi goto error; 6029*eb633035STom Caputi 6030*eb633035STom Caputi ret = spa_keystore_change_key(dsname, dcp); 6031*eb633035STom Caputi if (ret != 0) 6032*eb633035STom Caputi goto error; 6033*eb633035STom Caputi 6034*eb633035STom Caputi dsl_crypto_params_free(dcp, B_FALSE); 6035*eb633035STom Caputi 6036*eb633035STom Caputi return (0); 6037*eb633035STom Caputi 6038*eb633035STom Caputi error: 6039*eb633035STom Caputi dsl_crypto_params_free(dcp, B_TRUE); 6040*eb633035STom Caputi return (ret); 6041*eb633035STom Caputi } 6042*eb633035STom Caputi 60434445fffbSMatthew Ahrens static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST]; 60444445fffbSMatthew Ahrens 60454445fffbSMatthew Ahrens static void 60464445fffbSMatthew Ahrens zfs_ioctl_register_legacy(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 60474445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck, 60484445fffbSMatthew Ahrens boolean_t log_history, zfs_ioc_poolcheck_t pool_check) 60494445fffbSMatthew Ahrens { 60504445fffbSMatthew Ahrens zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST]; 60514445fffbSMatthew Ahrens 60524445fffbSMatthew Ahrens ASSERT3U(ioc, >=, ZFS_IOC_FIRST); 60534445fffbSMatthew Ahrens ASSERT3U(ioc, <, ZFS_IOC_LAST); 60544445fffbSMatthew Ahrens ASSERT3P(vec->zvec_legacy_func, ==, NULL); 60554445fffbSMatthew Ahrens ASSERT3P(vec->zvec_func, ==, NULL); 60564445fffbSMatthew Ahrens 60574445fffbSMatthew Ahrens vec->zvec_legacy_func = func; 60584445fffbSMatthew Ahrens vec->zvec_secpolicy = secpolicy; 60594445fffbSMatthew Ahrens vec->zvec_namecheck = namecheck; 60604445fffbSMatthew Ahrens vec->zvec_allow_log = log_history; 60614445fffbSMatthew Ahrens vec->zvec_pool_check = pool_check; 60624445fffbSMatthew Ahrens } 60634445fffbSMatthew Ahrens 60644445fffbSMatthew Ahrens /* 60654445fffbSMatthew Ahrens * See the block comment at the beginning of this file for details on 60664445fffbSMatthew Ahrens * each argument to this function. 60674445fffbSMatthew Ahrens */ 60684445fffbSMatthew Ahrens static void 60694445fffbSMatthew Ahrens zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func, 60704445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck, 60714445fffbSMatthew Ahrens zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist, 60724445fffbSMatthew Ahrens boolean_t allow_log) 60734445fffbSMatthew Ahrens { 60744445fffbSMatthew Ahrens zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST]; 60754445fffbSMatthew Ahrens 60764445fffbSMatthew Ahrens ASSERT3U(ioc, >=, ZFS_IOC_FIRST); 60774445fffbSMatthew Ahrens ASSERT3U(ioc, <, ZFS_IOC_LAST); 60784445fffbSMatthew Ahrens ASSERT3P(vec->zvec_legacy_func, ==, NULL); 60794445fffbSMatthew Ahrens ASSERT3P(vec->zvec_func, ==, NULL); 60804445fffbSMatthew Ahrens 60814445fffbSMatthew Ahrens /* if we are logging, the name must be valid */ 60824445fffbSMatthew Ahrens ASSERT(!allow_log || namecheck != NO_NAME); 60834445fffbSMatthew Ahrens 60844445fffbSMatthew Ahrens vec->zvec_name = name; 60854445fffbSMatthew Ahrens vec->zvec_func = func; 60864445fffbSMatthew Ahrens vec->zvec_secpolicy = secpolicy; 60874445fffbSMatthew Ahrens vec->zvec_namecheck = namecheck; 60884445fffbSMatthew Ahrens vec->zvec_pool_check = pool_check; 60894445fffbSMatthew Ahrens vec->zvec_smush_outnvlist = smush_outnvlist; 60904445fffbSMatthew Ahrens vec->zvec_allow_log = allow_log; 60914445fffbSMatthew Ahrens } 60924445fffbSMatthew Ahrens 60934445fffbSMatthew Ahrens static void 60944445fffbSMatthew Ahrens zfs_ioctl_register_pool(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 60954445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, boolean_t log_history, 60964445fffbSMatthew Ahrens zfs_ioc_poolcheck_t pool_check) 60974445fffbSMatthew Ahrens { 60984445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 60994445fffbSMatthew Ahrens POOL_NAME, log_history, pool_check); 61004445fffbSMatthew Ahrens } 61014445fffbSMatthew Ahrens 61024445fffbSMatthew Ahrens static void 61034445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 61044445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy, zfs_ioc_poolcheck_t pool_check) 61054445fffbSMatthew Ahrens { 61064445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 61074445fffbSMatthew Ahrens DATASET_NAME, B_FALSE, pool_check); 61084445fffbSMatthew Ahrens } 61094445fffbSMatthew Ahrens 61104445fffbSMatthew Ahrens static void 61114445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func) 61124445fffbSMatthew Ahrens { 61134445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, zfs_secpolicy_config, 61144445fffbSMatthew Ahrens POOL_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 61154445fffbSMatthew Ahrens } 61164445fffbSMatthew Ahrens 61174445fffbSMatthew Ahrens static void 61184445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 61194445fffbSMatthew Ahrens zfs_secpolicy_func_t *secpolicy) 61204445fffbSMatthew Ahrens { 61214445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 61224445fffbSMatthew Ahrens NO_NAME, B_FALSE, POOL_CHECK_NONE); 61234445fffbSMatthew Ahrens } 61244445fffbSMatthew Ahrens 61254445fffbSMatthew Ahrens static void 61264445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(zfs_ioc_t ioc, 61274445fffbSMatthew Ahrens zfs_ioc_legacy_func_t *func, zfs_secpolicy_func_t *secpolicy) 61284445fffbSMatthew Ahrens { 61294445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 61304445fffbSMatthew Ahrens DATASET_NAME, B_FALSE, POOL_CHECK_SUSPENDED); 61314445fffbSMatthew Ahrens } 61324445fffbSMatthew Ahrens 61334445fffbSMatthew Ahrens static void 61344445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func) 61354445fffbSMatthew Ahrens { 61364445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ioc, func, 61374445fffbSMatthew Ahrens zfs_secpolicy_read); 61384445fffbSMatthew Ahrens } 61394445fffbSMatthew Ahrens 61404445fffbSMatthew Ahrens static void 61414445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, 61429a686fbcSPaul Dagnelie zfs_secpolicy_func_t *secpolicy) 61434445fffbSMatthew Ahrens { 61444445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ioc, func, secpolicy, 61454445fffbSMatthew Ahrens DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 61464445fffbSMatthew Ahrens } 61474445fffbSMatthew Ahrens 61484445fffbSMatthew Ahrens static void 61494445fffbSMatthew Ahrens zfs_ioctl_init(void) 61504445fffbSMatthew Ahrens { 61514445fffbSMatthew Ahrens zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT, 61524445fffbSMatthew Ahrens zfs_ioc_snapshot, zfs_secpolicy_snapshot, POOL_NAME, 61534445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 61544445fffbSMatthew Ahrens 61554445fffbSMatthew Ahrens zfs_ioctl_register("log_history", ZFS_IOC_LOG_HISTORY, 61564445fffbSMatthew Ahrens zfs_ioc_log_history, zfs_secpolicy_log_history, NO_NAME, 61574445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE); 61584445fffbSMatthew Ahrens 61594445fffbSMatthew Ahrens zfs_ioctl_register("space_snaps", ZFS_IOC_SPACE_SNAPS, 61604445fffbSMatthew Ahrens zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME, 61614445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 61624445fffbSMatthew Ahrens 61634445fffbSMatthew Ahrens zfs_ioctl_register("send", ZFS_IOC_SEND_NEW, 61644445fffbSMatthew Ahrens zfs_ioc_send_new, zfs_secpolicy_send_new, DATASET_NAME, 61654445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 61664445fffbSMatthew Ahrens 61674445fffbSMatthew Ahrens zfs_ioctl_register("send_space", ZFS_IOC_SEND_SPACE, 61684445fffbSMatthew Ahrens zfs_ioc_send_space, zfs_secpolicy_read, DATASET_NAME, 61694445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 61704445fffbSMatthew Ahrens 61714445fffbSMatthew Ahrens zfs_ioctl_register("create", ZFS_IOC_CREATE, 61724445fffbSMatthew Ahrens zfs_ioc_create, zfs_secpolicy_create_clone, DATASET_NAME, 61734445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 61744445fffbSMatthew Ahrens 61754445fffbSMatthew Ahrens zfs_ioctl_register("clone", ZFS_IOC_CLONE, 61764445fffbSMatthew Ahrens zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME, 61774445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 61784445fffbSMatthew Ahrens 61795cabbc6bSPrashanth Sreenivasa zfs_ioctl_register("remap", ZFS_IOC_REMAP, 61805cabbc6bSPrashanth Sreenivasa zfs_ioc_remap, zfs_secpolicy_remap, DATASET_NAME, 61815cabbc6bSPrashanth Sreenivasa POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE); 61825cabbc6bSPrashanth Sreenivasa 61834445fffbSMatthew Ahrens zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS, 61844445fffbSMatthew Ahrens zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME, 61854445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 61864445fffbSMatthew Ahrens 61873b2aab18SMatthew Ahrens zfs_ioctl_register("hold", ZFS_IOC_HOLD, 61883b2aab18SMatthew Ahrens zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME, 61893b2aab18SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 61903b2aab18SMatthew Ahrens zfs_ioctl_register("release", ZFS_IOC_RELEASE, 61913b2aab18SMatthew Ahrens zfs_ioc_release, zfs_secpolicy_release, POOL_NAME, 61923b2aab18SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 61933b2aab18SMatthew Ahrens 61943b2aab18SMatthew Ahrens zfs_ioctl_register("get_holds", ZFS_IOC_GET_HOLDS, 61953b2aab18SMatthew Ahrens zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, 61963b2aab18SMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 61973b2aab18SMatthew Ahrens 6198a7027df1SMatthew Ahrens zfs_ioctl_register("rollback", ZFS_IOC_ROLLBACK, 6199a7027df1SMatthew Ahrens zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, 6200a7027df1SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE); 6201a7027df1SMatthew Ahrens 620278f17100SMatthew Ahrens zfs_ioctl_register("bookmark", ZFS_IOC_BOOKMARK, 620378f17100SMatthew Ahrens zfs_ioc_bookmark, zfs_secpolicy_bookmark, POOL_NAME, 620478f17100SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 620578f17100SMatthew Ahrens 620678f17100SMatthew Ahrens zfs_ioctl_register("get_bookmarks", ZFS_IOC_GET_BOOKMARKS, 620778f17100SMatthew Ahrens zfs_ioc_get_bookmarks, zfs_secpolicy_read, DATASET_NAME, 620878f17100SMatthew Ahrens POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); 620978f17100SMatthew Ahrens 621078f17100SMatthew Ahrens zfs_ioctl_register("destroy_bookmarks", ZFS_IOC_DESTROY_BOOKMARKS, 621178f17100SMatthew Ahrens zfs_ioc_destroy_bookmarks, zfs_secpolicy_destroy_bookmarks, 621278f17100SMatthew Ahrens POOL_NAME, 621378f17100SMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 621478f17100SMatthew Ahrens 6215dfc11533SChris Williamson zfs_ioctl_register("channel_program", ZFS_IOC_CHANNEL_PROGRAM, 6216dfc11533SChris Williamson zfs_ioc_channel_program, zfs_secpolicy_config, 6217dfc11533SChris Williamson POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, 6218dfc11533SChris Williamson B_TRUE); 6219dfc11533SChris Williamson 622086714001SSerapheim Dimitropoulos zfs_ioctl_register("zpool_checkpoint", ZFS_IOC_POOL_CHECKPOINT, 622186714001SSerapheim Dimitropoulos zfs_ioc_pool_checkpoint, zfs_secpolicy_config, POOL_NAME, 622286714001SSerapheim Dimitropoulos POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 622386714001SSerapheim Dimitropoulos 622486714001SSerapheim Dimitropoulos zfs_ioctl_register("zpool_discard_checkpoint", 622586714001SSerapheim Dimitropoulos ZFS_IOC_POOL_DISCARD_CHECKPOINT, zfs_ioc_pool_discard_checkpoint, 622686714001SSerapheim Dimitropoulos zfs_secpolicy_config, POOL_NAME, 622786714001SSerapheim Dimitropoulos POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 622886714001SSerapheim Dimitropoulos 6229094e47e9SGeorge Wilson zfs_ioctl_register("initialize", ZFS_IOC_POOL_INITIALIZE, 6230094e47e9SGeorge Wilson zfs_ioc_pool_initialize, zfs_secpolicy_config, POOL_NAME, 6231094e47e9SGeorge Wilson POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); 6232094e47e9SGeorge Wilson 62339c2acf00SAlek Pinchuk zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC, 62349c2acf00SAlek Pinchuk zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME, 62359c2acf00SAlek Pinchuk POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE); 62369c2acf00SAlek Pinchuk 6237*eb633035STom Caputi zfs_ioctl_register("load-key", ZFS_IOC_LOAD_KEY, 6238*eb633035STom Caputi zfs_ioc_load_key, zfs_secpolicy_load_key, 6239*eb633035STom Caputi DATASET_NAME, POOL_CHECK_SUSPENDED, B_TRUE, B_TRUE); 6240*eb633035STom Caputi zfs_ioctl_register("unload-key", ZFS_IOC_UNLOAD_KEY, 6241*eb633035STom Caputi zfs_ioc_unload_key, zfs_secpolicy_load_key, 6242*eb633035STom Caputi DATASET_NAME, POOL_CHECK_SUSPENDED, B_TRUE, B_TRUE); 6243*eb633035STom Caputi zfs_ioctl_register("change-key", ZFS_IOC_CHANGE_KEY, 6244*eb633035STom Caputi zfs_ioc_change_key, zfs_secpolicy_change_key, 6245*eb633035STom Caputi DATASET_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, 6246*eb633035STom Caputi B_TRUE, B_TRUE); 6247*eb633035STom Caputi 62484445fffbSMatthew Ahrens /* IOCTLS that use the legacy function signature */ 62494445fffbSMatthew Ahrens 62504445fffbSMatthew Ahrens zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, 62514445fffbSMatthew Ahrens zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_READONLY); 62524445fffbSMatthew Ahrens 62534445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_CREATE, zfs_ioc_pool_create, 62544445fffbSMatthew Ahrens zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); 62554445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SCAN, 62564445fffbSMatthew Ahrens zfs_ioc_pool_scan); 62574445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_UPGRADE, 62584445fffbSMatthew Ahrens zfs_ioc_pool_upgrade); 62594445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ADD, 62604445fffbSMatthew Ahrens zfs_ioc_vdev_add); 62614445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_REMOVE, 62624445fffbSMatthew Ahrens zfs_ioc_vdev_remove); 62634445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SET_STATE, 62644445fffbSMatthew Ahrens zfs_ioc_vdev_set_state); 62654445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ATTACH, 62664445fffbSMatthew Ahrens zfs_ioc_vdev_attach); 62674445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_DETACH, 62684445fffbSMatthew Ahrens zfs_ioc_vdev_detach); 62694445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETPATH, 62704445fffbSMatthew Ahrens zfs_ioc_vdev_setpath); 62714445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETFRU, 62724445fffbSMatthew Ahrens zfs_ioc_vdev_setfru); 62734445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SET_PROPS, 62744445fffbSMatthew Ahrens zfs_ioc_pool_set_props); 62754445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SPLIT, 62764445fffbSMatthew Ahrens zfs_ioc_vdev_split); 62774445fffbSMatthew Ahrens zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_REGUID, 62784445fffbSMatthew Ahrens zfs_ioc_pool_reguid); 62794445fffbSMatthew Ahrens 62804445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_POOL_CONFIGS, 62814445fffbSMatthew Ahrens zfs_ioc_pool_configs, zfs_secpolicy_none); 62824445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_POOL_TRYIMPORT, 62834445fffbSMatthew Ahrens zfs_ioc_pool_tryimport, zfs_secpolicy_config); 62844445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_INJECT_FAULT, 62854445fffbSMatthew Ahrens zfs_ioc_inject_fault, zfs_secpolicy_inject); 62864445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_CLEAR_FAULT, 62874445fffbSMatthew Ahrens zfs_ioc_clear_fault, zfs_secpolicy_inject); 62884445fffbSMatthew Ahrens zfs_ioctl_register_pool_meta(ZFS_IOC_INJECT_LIST_NEXT, 62894445fffbSMatthew Ahrens zfs_ioc_inject_list_next, zfs_secpolicy_inject); 62904445fffbSMatthew Ahrens 62914445fffbSMatthew Ahrens /* 62924445fffbSMatthew Ahrens * pool destroy, and export don't log the history as part of 62934445fffbSMatthew Ahrens * zfsdev_ioctl, but rather zfs_ioc_pool_export 62944445fffbSMatthew Ahrens * does the logging of those commands. 62954445fffbSMatthew Ahrens */ 62964445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_DESTROY, zfs_ioc_pool_destroy, 62974445fffbSMatthew Ahrens zfs_secpolicy_config, B_FALSE, POOL_CHECK_NONE); 62984445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_EXPORT, zfs_ioc_pool_export, 62994445fffbSMatthew Ahrens zfs_secpolicy_config, B_FALSE, POOL_CHECK_NONE); 63004445fffbSMatthew Ahrens 63014445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_STATS, zfs_ioc_pool_stats, 63024445fffbSMatthew Ahrens zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE); 63034445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_PROPS, zfs_ioc_pool_get_props, 63044445fffbSMatthew Ahrens zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE); 63054445fffbSMatthew Ahrens 63064445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_ERROR_LOG, zfs_ioc_error_log, 63074445fffbSMatthew Ahrens zfs_secpolicy_inject, B_FALSE, POOL_CHECK_SUSPENDED); 63084445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_DSOBJ_TO_DSNAME, 63094445fffbSMatthew Ahrens zfs_ioc_dsobj_to_dsname, 63104445fffbSMatthew Ahrens zfs_secpolicy_diff, B_FALSE, POOL_CHECK_SUSPENDED); 63114445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_HISTORY, 63124445fffbSMatthew Ahrens zfs_ioc_pool_get_history, 63134445fffbSMatthew Ahrens zfs_secpolicy_config, B_FALSE, POOL_CHECK_SUSPENDED); 63144445fffbSMatthew Ahrens 63154445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_IMPORT, zfs_ioc_pool_import, 63164445fffbSMatthew Ahrens zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); 63174445fffbSMatthew Ahrens 63184445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear, 6319f4c1745bSloli zfs_secpolicy_config, B_TRUE, POOL_CHECK_READONLY); 63204445fffbSMatthew Ahrens zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen, 63214445fffbSMatthew Ahrens zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); 63224445fffbSMatthew Ahrens 63234445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN, 63244445fffbSMatthew Ahrens zfs_ioc_space_written); 63254445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_RECVD_PROPS, 63264445fffbSMatthew Ahrens zfs_ioc_objset_recvd_props); 63274445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_NEXT_OBJ, 63284445fffbSMatthew Ahrens zfs_ioc_next_obj); 63294445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_GET_FSACL, 63304445fffbSMatthew Ahrens zfs_ioc_get_fsacl); 63314445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_STATS, 63324445fffbSMatthew Ahrens zfs_ioc_objset_stats); 63334445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_ZPLPROPS, 63344445fffbSMatthew Ahrens zfs_ioc_objset_zplprops); 63354445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_DATASET_LIST_NEXT, 63364445fffbSMatthew Ahrens zfs_ioc_dataset_list_next); 63374445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_SNAPSHOT_LIST_NEXT, 63384445fffbSMatthew Ahrens zfs_ioc_snapshot_list_next); 63394445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read(ZFS_IOC_SEND_PROGRESS, 63404445fffbSMatthew Ahrens zfs_ioc_send_progress); 63414445fffbSMatthew Ahrens 63424445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_DIFF, 63434445fffbSMatthew Ahrens zfs_ioc_diff, zfs_secpolicy_diff); 63444445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_STATS, 63454445fffbSMatthew Ahrens zfs_ioc_obj_to_stats, zfs_secpolicy_diff); 63464445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_PATH, 63474445fffbSMatthew Ahrens zfs_ioc_obj_to_path, zfs_secpolicy_diff); 63484445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_USERSPACE_ONE, 63494445fffbSMatthew Ahrens zfs_ioc_userspace_one, zfs_secpolicy_userspace_one); 63504445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_USERSPACE_MANY, 63514445fffbSMatthew Ahrens zfs_ioc_userspace_many, zfs_secpolicy_userspace_many); 63524445fffbSMatthew Ahrens zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_SEND, 63534445fffbSMatthew Ahrens zfs_ioc_send, zfs_secpolicy_send); 63544445fffbSMatthew Ahrens 63554445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_PROP, zfs_ioc_set_prop, 63564445fffbSMatthew Ahrens zfs_secpolicy_none); 63574445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy, 63584445fffbSMatthew Ahrens zfs_secpolicy_destroy); 63594445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_RENAME, zfs_ioc_rename, 63604445fffbSMatthew Ahrens zfs_secpolicy_rename); 63614445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_RECV, zfs_ioc_recv, 63624445fffbSMatthew Ahrens zfs_secpolicy_recv); 63634445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_PROMOTE, zfs_ioc_promote, 63644445fffbSMatthew Ahrens zfs_secpolicy_promote); 63654445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_INHERIT_PROP, 63664445fffbSMatthew Ahrens zfs_ioc_inherit_prop, zfs_secpolicy_inherit_prop); 63674445fffbSMatthew Ahrens zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_FSACL, zfs_ioc_set_fsacl, 63684445fffbSMatthew Ahrens zfs_secpolicy_set_fsacl); 63694445fffbSMatthew Ahrens 63704445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_SHARE, zfs_ioc_share, 63714445fffbSMatthew Ahrens zfs_secpolicy_share, POOL_CHECK_NONE); 63724445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_SMB_ACL, zfs_ioc_smb_acl, 63734445fffbSMatthew Ahrens zfs_secpolicy_smb_acl, POOL_CHECK_NONE); 63744445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_USERSPACE_UPGRADE, 63754445fffbSMatthew Ahrens zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade, 63764445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 63774445fffbSMatthew Ahrens zfs_ioctl_register_dataset_nolog(ZFS_IOC_TMP_SNAPSHOT, 63784445fffbSMatthew Ahrens zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot, 63794445fffbSMatthew Ahrens POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); 63804445fffbSMatthew Ahrens } 6381fa9e4066Sahrens 638254d692b7SGeorge Wilson int 6383f9af39baSGeorge Wilson pool_status_check(const char *name, zfs_ioc_namecheck_t type, 6384f9af39baSGeorge Wilson zfs_ioc_poolcheck_t check) 638554d692b7SGeorge Wilson { 638654d692b7SGeorge Wilson spa_t *spa; 638754d692b7SGeorge Wilson int error; 638854d692b7SGeorge Wilson 638954d692b7SGeorge Wilson ASSERT(type == POOL_NAME || type == DATASET_NAME); 639054d692b7SGeorge Wilson 6391f9af39baSGeorge Wilson if (check & POOL_CHECK_NONE) 6392f9af39baSGeorge Wilson return (0); 6393f9af39baSGeorge Wilson 639414843421SMatthew Ahrens error = spa_open(name, &spa, FTAG); 639554d692b7SGeorge Wilson if (error == 0) { 6396f9af39baSGeorge Wilson if ((check & POOL_CHECK_SUSPENDED) && spa_suspended(spa)) 6397be6fd75aSMatthew Ahrens error = SET_ERROR(EAGAIN); 6398f9af39baSGeorge Wilson else if ((check & POOL_CHECK_READONLY) && !spa_writeable(spa)) 6399be6fd75aSMatthew Ahrens error = SET_ERROR(EROFS); 640054d692b7SGeorge Wilson spa_close(spa, FTAG); 640154d692b7SGeorge Wilson } 640254d692b7SGeorge Wilson return (error); 640354d692b7SGeorge Wilson } 640454d692b7SGeorge Wilson 6405c99e4bdcSChris Kirby /* 6406c99e4bdcSChris Kirby * Find a free minor number. 6407c99e4bdcSChris Kirby */ 6408c99e4bdcSChris Kirby minor_t 6409c99e4bdcSChris Kirby zfsdev_minor_alloc(void) 6410c99e4bdcSChris Kirby { 6411c99e4bdcSChris Kirby static minor_t last_minor; 6412c99e4bdcSChris Kirby minor_t m; 6413c99e4bdcSChris Kirby 6414c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 6415c99e4bdcSChris Kirby 6416c99e4bdcSChris Kirby for (m = last_minor + 1; m != last_minor; m++) { 6417c99e4bdcSChris Kirby if (m > ZFSDEV_MAX_MINOR) 6418c99e4bdcSChris Kirby m = 1; 6419c99e4bdcSChris Kirby if (ddi_get_soft_state(zfsdev_state, m) == NULL) { 6420c99e4bdcSChris Kirby last_minor = m; 6421c99e4bdcSChris Kirby return (m); 6422c99e4bdcSChris Kirby } 6423c99e4bdcSChris Kirby } 6424c99e4bdcSChris Kirby 6425c99e4bdcSChris Kirby return (0); 6426c99e4bdcSChris Kirby } 6427c99e4bdcSChris Kirby 6428c99e4bdcSChris Kirby static int 6429c99e4bdcSChris Kirby zfs_ctldev_init(dev_t *devp) 6430c99e4bdcSChris Kirby { 6431c99e4bdcSChris Kirby minor_t minor; 6432c99e4bdcSChris Kirby zfs_soft_state_t *zs; 6433c99e4bdcSChris Kirby 6434c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 6435c99e4bdcSChris Kirby ASSERT(getminor(*devp) == 0); 6436c99e4bdcSChris Kirby 6437c99e4bdcSChris Kirby minor = zfsdev_minor_alloc(); 6438c99e4bdcSChris Kirby if (minor == 0) 6439be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 6440c99e4bdcSChris Kirby 6441c99e4bdcSChris Kirby if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) 6442be6fd75aSMatthew Ahrens return (SET_ERROR(EAGAIN)); 6443c99e4bdcSChris Kirby 6444c99e4bdcSChris Kirby *devp = makedevice(getemajor(*devp), minor); 6445c99e4bdcSChris Kirby 6446c99e4bdcSChris Kirby zs = ddi_get_soft_state(zfsdev_state, minor); 6447c99e4bdcSChris Kirby zs->zss_type = ZSST_CTLDEV; 6448c99e4bdcSChris Kirby zfs_onexit_init((zfs_onexit_t **)&zs->zss_data); 6449c99e4bdcSChris Kirby 6450c99e4bdcSChris Kirby return (0); 6451c99e4bdcSChris Kirby } 6452c99e4bdcSChris Kirby 6453c99e4bdcSChris Kirby static void 6454c99e4bdcSChris Kirby zfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor) 6455c99e4bdcSChris Kirby { 6456c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 6457c99e4bdcSChris Kirby 6458c99e4bdcSChris Kirby zfs_onexit_destroy(zo); 6459c99e4bdcSChris Kirby ddi_soft_state_free(zfsdev_state, minor); 6460c99e4bdcSChris Kirby } 6461c99e4bdcSChris Kirby 6462c99e4bdcSChris Kirby void * 6463c99e4bdcSChris Kirby zfsdev_get_soft_state(minor_t minor, enum zfs_soft_state_type which) 6464c99e4bdcSChris Kirby { 6465c99e4bdcSChris Kirby zfs_soft_state_t *zp; 6466c99e4bdcSChris Kirby 6467c99e4bdcSChris Kirby zp = ddi_get_soft_state(zfsdev_state, minor); 6468c99e4bdcSChris Kirby if (zp == NULL || zp->zss_type != which) 6469c99e4bdcSChris Kirby return (NULL); 6470c99e4bdcSChris Kirby 6471c99e4bdcSChris Kirby return (zp->zss_data); 6472c99e4bdcSChris Kirby } 6473c99e4bdcSChris Kirby 6474c99e4bdcSChris Kirby static int 6475c99e4bdcSChris Kirby zfsdev_open(dev_t *devp, int flag, int otyp, cred_t *cr) 6476c99e4bdcSChris Kirby { 6477c99e4bdcSChris Kirby int error = 0; 6478c99e4bdcSChris Kirby 6479c99e4bdcSChris Kirby if (getminor(*devp) != 0) 6480c99e4bdcSChris Kirby return (zvol_open(devp, flag, otyp, cr)); 6481c99e4bdcSChris Kirby 6482c99e4bdcSChris Kirby /* This is the control device. Allocate a new minor if requested. */ 6483c99e4bdcSChris Kirby if (flag & FEXCL) { 6484c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 6485c99e4bdcSChris Kirby error = zfs_ctldev_init(devp); 6486c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 6487c99e4bdcSChris Kirby } 6488c99e4bdcSChris Kirby 6489c99e4bdcSChris Kirby return (error); 6490c99e4bdcSChris Kirby } 6491c99e4bdcSChris Kirby 6492c99e4bdcSChris Kirby static int 6493c99e4bdcSChris Kirby zfsdev_close(dev_t dev, int flag, int otyp, cred_t *cr) 6494c99e4bdcSChris Kirby { 6495c99e4bdcSChris Kirby zfs_onexit_t *zo; 6496c99e4bdcSChris Kirby minor_t minor = getminor(dev); 6497c99e4bdcSChris Kirby 6498c99e4bdcSChris Kirby if (minor == 0) 6499c99e4bdcSChris Kirby return (0); 6500c99e4bdcSChris Kirby 6501c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 6502c99e4bdcSChris Kirby zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); 6503c99e4bdcSChris Kirby if (zo == NULL) { 6504c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 6505c99e4bdcSChris Kirby return (zvol_close(dev, flag, otyp, cr)); 6506c99e4bdcSChris Kirby } 6507c99e4bdcSChris Kirby zfs_ctldev_destroy(zo, minor); 6508c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 6509c99e4bdcSChris Kirby 6510c99e4bdcSChris Kirby return (0); 6511c99e4bdcSChris Kirby } 6512c99e4bdcSChris Kirby 6513fa9e4066Sahrens static int 6514fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 6515fa9e4066Sahrens { 6516fa9e4066Sahrens zfs_cmd_t *zc; 65174445fffbSMatthew Ahrens uint_t vecnum; 65184445fffbSMatthew Ahrens int error, rc, len; 6519c99e4bdcSChris Kirby minor_t minor = getminor(dev); 65204445fffbSMatthew Ahrens const zfs_ioc_vec_t *vec; 65214445fffbSMatthew Ahrens char *saved_poolname = NULL; 65224445fffbSMatthew Ahrens nvlist_t *innvl = NULL; 6523fa9e4066Sahrens 6524c99e4bdcSChris Kirby if (minor != 0 && 6525c99e4bdcSChris Kirby zfsdev_get_soft_state(minor, ZSST_CTLDEV) == NULL) 6526fa9e4066Sahrens return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); 6527fa9e4066Sahrens 65284445fffbSMatthew Ahrens vecnum = cmd - ZFS_IOC_FIRST; 652991ebeef5Sahrens ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); 6530fa9e4066Sahrens 65314445fffbSMatthew Ahrens if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 6532be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 65334445fffbSMatthew Ahrens vec = &zfs_ioc_vec[vecnum]; 6534fa9e4066Sahrens 6535fa9e4066Sahrens zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 6536fa9e4066Sahrens 6537478ed9adSEric Taylor error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag); 65384445fffbSMatthew Ahrens if (error != 0) { 6539be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 65404445fffbSMatthew Ahrens goto out; 65414445fffbSMatthew Ahrens } 6542fa9e4066Sahrens 65434445fffbSMatthew Ahrens zc->zc_iflags = flag & FKIOCTL; 65444445fffbSMatthew Ahrens if (zc->zc_nvlist_src_size != 0) { 65454445fffbSMatthew Ahrens error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, 65464445fffbSMatthew Ahrens zc->zc_iflags, &innvl); 65474445fffbSMatthew Ahrens if (error != 0) 65484445fffbSMatthew Ahrens goto out; 65494445fffbSMatthew Ahrens } 6550fa9e4066Sahrens 6551fa9e4066Sahrens /* 6552fa9e4066Sahrens * Ensure that all pool/dataset names are valid before we pass down to 6553fa9e4066Sahrens * the lower layers. 6554fa9e4066Sahrens */ 65554445fffbSMatthew Ahrens zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 65564445fffbSMatthew Ahrens switch (vec->zvec_namecheck) { 65574445fffbSMatthew Ahrens case POOL_NAME: 65584445fffbSMatthew Ahrens if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 6559be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 65604445fffbSMatthew Ahrens else 6561f9af39baSGeorge Wilson error = pool_status_check(zc->zc_name, 65624445fffbSMatthew Ahrens vec->zvec_namecheck, vec->zvec_pool_check); 65634445fffbSMatthew Ahrens break; 6564fa9e4066Sahrens 65654445fffbSMatthew Ahrens case DATASET_NAME: 65664445fffbSMatthew Ahrens if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 6567be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 65684445fffbSMatthew Ahrens else 6569f9af39baSGeorge Wilson error = pool_status_check(zc->zc_name, 65704445fffbSMatthew Ahrens vec->zvec_namecheck, vec->zvec_pool_check); 65714445fffbSMatthew Ahrens break; 65725ad82045Snd 65734445fffbSMatthew Ahrens case NO_NAME: 65744445fffbSMatthew Ahrens break; 6575fa9e4066Sahrens } 6576fa9e4066Sahrens 6577fa9e4066Sahrens 657845b17475SAlex Wilson if (error == 0) 65794445fffbSMatthew Ahrens error = vec->zvec_secpolicy(zc, innvl, cr); 65804445fffbSMatthew Ahrens 65814445fffbSMatthew Ahrens if (error != 0) 65824445fffbSMatthew Ahrens goto out; 65834445fffbSMatthew Ahrens 65844445fffbSMatthew Ahrens /* legacy ioctls can modify zc_name */ 658578f17100SMatthew Ahrens len = strcspn(zc->zc_name, "/@#") + 1; 65864445fffbSMatthew Ahrens saved_poolname = kmem_alloc(len, KM_SLEEP); 65874445fffbSMatthew Ahrens (void) strlcpy(saved_poolname, zc->zc_name, len); 65884445fffbSMatthew Ahrens 65894445fffbSMatthew Ahrens if (vec->zvec_func != NULL) { 65904445fffbSMatthew Ahrens nvlist_t *outnvl; 65914445fffbSMatthew Ahrens int puterror = 0; 65924445fffbSMatthew Ahrens spa_t *spa; 65934445fffbSMatthew Ahrens nvlist_t *lognv = NULL; 65944445fffbSMatthew Ahrens 65954445fffbSMatthew Ahrens ASSERT(vec->zvec_legacy_func == NULL); 65964445fffbSMatthew Ahrens 65974445fffbSMatthew Ahrens /* 65984445fffbSMatthew Ahrens * Add the innvl to the lognv before calling the func, 65994445fffbSMatthew Ahrens * in case the func changes the innvl. 66004445fffbSMatthew Ahrens */ 66014445fffbSMatthew Ahrens if (vec->zvec_allow_log) { 66024445fffbSMatthew Ahrens lognv = fnvlist_alloc(); 66034445fffbSMatthew Ahrens fnvlist_add_string(lognv, ZPOOL_HIST_IOCTL, 66044445fffbSMatthew Ahrens vec->zvec_name); 66054445fffbSMatthew Ahrens if (!nvlist_empty(innvl)) { 66064445fffbSMatthew Ahrens fnvlist_add_nvlist(lognv, ZPOOL_HIST_INPUT_NVL, 66074445fffbSMatthew Ahrens innvl); 66084445fffbSMatthew Ahrens } 66094445fffbSMatthew Ahrens } 66104445fffbSMatthew Ahrens 66114445fffbSMatthew Ahrens outnvl = fnvlist_alloc(); 66124445fffbSMatthew Ahrens error = vec->zvec_func(zc->zc_name, innvl, outnvl); 66134445fffbSMatthew Ahrens 6614dfc11533SChris Williamson /* 6615d0cb1fb9SDon Brady * Some commands can partially execute, modify state, and still 6616dfc11533SChris Williamson * return an error. In these cases, attempt to record what 6617dfc11533SChris Williamson * was modified. 6618dfc11533SChris Williamson */ 6619dfc11533SChris Williamson if ((error == 0 || 6620dfc11533SChris Williamson (cmd == ZFS_IOC_CHANNEL_PROGRAM && error != EINVAL)) && 6621dfc11533SChris Williamson vec->zvec_allow_log && 66224445fffbSMatthew Ahrens spa_open(zc->zc_name, &spa, FTAG) == 0) { 66234445fffbSMatthew Ahrens if (!nvlist_empty(outnvl)) { 66244445fffbSMatthew Ahrens fnvlist_add_nvlist(lognv, ZPOOL_HIST_OUTPUT_NVL, 66254445fffbSMatthew Ahrens outnvl); 66264445fffbSMatthew Ahrens } 6627dfc11533SChris Williamson if (error != 0) { 6628dfc11533SChris Williamson fnvlist_add_int64(lognv, ZPOOL_HIST_ERRNO, 6629dfc11533SChris Williamson error); 6630dfc11533SChris Williamson } 66314445fffbSMatthew Ahrens (void) spa_history_log_nvl(spa, lognv); 66324445fffbSMatthew Ahrens spa_close(spa, FTAG); 66334445fffbSMatthew Ahrens } 66344445fffbSMatthew Ahrens fnvlist_free(lognv); 66354445fffbSMatthew Ahrens 66364445fffbSMatthew Ahrens if (!nvlist_empty(outnvl) || zc->zc_nvlist_dst_size != 0) { 66374445fffbSMatthew Ahrens int smusherror = 0; 66384445fffbSMatthew Ahrens if (vec->zvec_smush_outnvlist) { 66394445fffbSMatthew Ahrens smusherror = nvlist_smush(outnvl, 66404445fffbSMatthew Ahrens zc->zc_nvlist_dst_size); 66414445fffbSMatthew Ahrens } 66424445fffbSMatthew Ahrens if (smusherror == 0) 66434445fffbSMatthew Ahrens puterror = put_nvlist(zc, outnvl); 66444445fffbSMatthew Ahrens } 66454445fffbSMatthew Ahrens 66464445fffbSMatthew Ahrens if (puterror != 0) 66474445fffbSMatthew Ahrens error = puterror; 66484445fffbSMatthew Ahrens 66494445fffbSMatthew Ahrens nvlist_free(outnvl); 66504445fffbSMatthew Ahrens } else { 66514445fffbSMatthew Ahrens error = vec->zvec_legacy_func(zc); 66524445fffbSMatthew Ahrens } 66534445fffbSMatthew Ahrens 66544445fffbSMatthew Ahrens out: 66554445fffbSMatthew Ahrens nvlist_free(innvl); 6656478ed9adSEric Taylor rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag); 66574445fffbSMatthew Ahrens if (error == 0 && rc != 0) 6658be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 66594445fffbSMatthew Ahrens if (error == 0 && vec->zvec_allow_log) { 66604445fffbSMatthew Ahrens char *s = tsd_get(zfs_allow_log_key); 66614445fffbSMatthew Ahrens if (s != NULL) 66624445fffbSMatthew Ahrens strfree(s); 66634445fffbSMatthew Ahrens (void) tsd_set(zfs_allow_log_key, saved_poolname); 66644445fffbSMatthew Ahrens } else { 66654445fffbSMatthew Ahrens if (saved_poolname != NULL) 66664445fffbSMatthew Ahrens strfree(saved_poolname); 6667ecd6cf80Smarks } 6668fa9e4066Sahrens 6669fa9e4066Sahrens kmem_free(zc, sizeof (zfs_cmd_t)); 6670fa9e4066Sahrens return (error); 6671fa9e4066Sahrens } 6672fa9e4066Sahrens 6673fa9e4066Sahrens static int 6674fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6675fa9e4066Sahrens { 6676fa9e4066Sahrens if (cmd != DDI_ATTACH) 6677fa9e4066Sahrens return (DDI_FAILURE); 6678fa9e4066Sahrens 6679fa9e4066Sahrens if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, 6680fa9e4066Sahrens DDI_PSEUDO, 0) == DDI_FAILURE) 6681fa9e4066Sahrens return (DDI_FAILURE); 6682fa9e4066Sahrens 6683fa9e4066Sahrens zfs_dip = dip; 6684fa9e4066Sahrens 6685fa9e4066Sahrens ddi_report_dev(dip); 6686fa9e4066Sahrens 6687fa9e4066Sahrens return (DDI_SUCCESS); 6688fa9e4066Sahrens } 6689fa9e4066Sahrens 6690fa9e4066Sahrens static int 6691fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 6692fa9e4066Sahrens { 6693fa9e4066Sahrens if (spa_busy() || zfs_busy() || zvol_busy()) 6694fa9e4066Sahrens return (DDI_FAILURE); 6695fa9e4066Sahrens 6696fa9e4066Sahrens if (cmd != DDI_DETACH) 6697fa9e4066Sahrens return (DDI_FAILURE); 6698fa9e4066Sahrens 6699fa9e4066Sahrens zfs_dip = NULL; 6700fa9e4066Sahrens 6701fa9e4066Sahrens ddi_prop_remove_all(dip); 6702fa9e4066Sahrens ddi_remove_minor_node(dip, NULL); 6703fa9e4066Sahrens 6704fa9e4066Sahrens return (DDI_SUCCESS); 6705fa9e4066Sahrens } 6706fa9e4066Sahrens 6707fa9e4066Sahrens /*ARGSUSED*/ 6708fa9e4066Sahrens static int 6709fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 6710fa9e4066Sahrens { 6711fa9e4066Sahrens switch (infocmd) { 6712fa9e4066Sahrens case DDI_INFO_DEVT2DEVINFO: 6713fa9e4066Sahrens *result = zfs_dip; 6714fa9e4066Sahrens return (DDI_SUCCESS); 6715fa9e4066Sahrens 6716fa9e4066Sahrens case DDI_INFO_DEVT2INSTANCE: 6717a0965f35Sbonwick *result = (void *)0; 6718fa9e4066Sahrens return (DDI_SUCCESS); 6719fa9e4066Sahrens } 6720fa9e4066Sahrens 6721fa9e4066Sahrens return (DDI_FAILURE); 6722fa9e4066Sahrens } 6723fa9e4066Sahrens 6724fa9e4066Sahrens /* 6725fa9e4066Sahrens * OK, so this is a little weird. 6726fa9e4066Sahrens * 6727fa9e4066Sahrens * /dev/zfs is the control node, i.e. minor 0. 6728fa9e4066Sahrens * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 6729fa9e4066Sahrens * 6730fa9e4066Sahrens * /dev/zfs has basically nothing to do except serve up ioctls, 6731fa9e4066Sahrens * so most of the standard driver entry points are in zvol.c. 6732fa9e4066Sahrens */ 6733fa9e4066Sahrens static struct cb_ops zfs_cb_ops = { 6734c99e4bdcSChris Kirby zfsdev_open, /* open */ 6735c99e4bdcSChris Kirby zfsdev_close, /* close */ 6736fa9e4066Sahrens zvol_strategy, /* strategy */ 6737fa9e4066Sahrens nodev, /* print */ 6738e7cbe64fSgw zvol_dump, /* dump */ 6739fa9e4066Sahrens zvol_read, /* read */ 6740fa9e4066Sahrens zvol_write, /* write */ 6741fa9e4066Sahrens zfsdev_ioctl, /* ioctl */ 6742fa9e4066Sahrens nodev, /* devmap */ 6743fa9e4066Sahrens nodev, /* mmap */ 6744fa9e4066Sahrens nodev, /* segmap */ 6745fa9e4066Sahrens nochpoll, /* poll */ 6746fa9e4066Sahrens ddi_prop_op, /* prop_op */ 6747fa9e4066Sahrens NULL, /* streamtab */ 6748fa9e4066Sahrens D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ 6749fa9e4066Sahrens CB_REV, /* version */ 6750feb08c6bSbillm nodev, /* async read */ 6751feb08c6bSbillm nodev, /* async write */ 6752fa9e4066Sahrens }; 6753fa9e4066Sahrens 6754fa9e4066Sahrens static struct dev_ops zfs_dev_ops = { 6755fa9e4066Sahrens DEVO_REV, /* version */ 6756fa9e4066Sahrens 0, /* refcnt */ 6757fa9e4066Sahrens zfs_info, /* info */ 6758fa9e4066Sahrens nulldev, /* identify */ 6759fa9e4066Sahrens nulldev, /* probe */ 6760fa9e4066Sahrens zfs_attach, /* attach */ 6761fa9e4066Sahrens zfs_detach, /* detach */ 6762fa9e4066Sahrens nodev, /* reset */ 6763fa9e4066Sahrens &zfs_cb_ops, /* driver operations */ 676419397407SSherry Moore NULL, /* no bus operations */ 676519397407SSherry Moore NULL, /* power */ 676619397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 6767fa9e4066Sahrens }; 6768fa9e4066Sahrens 6769fa9e4066Sahrens static struct modldrv zfs_modldrv = { 677019397407SSherry Moore &mod_driverops, 677119397407SSherry Moore "ZFS storage pool", 677219397407SSherry Moore &zfs_dev_ops 6773fa9e4066Sahrens }; 6774fa9e4066Sahrens 6775fa9e4066Sahrens static struct modlinkage modlinkage = { 6776fa9e4066Sahrens MODREV_1, 6777fa9e4066Sahrens (void *)&zfs_modlfs, 6778fa9e4066Sahrens (void *)&zfs_modldrv, 6779fa9e4066Sahrens NULL 6780fa9e4066Sahrens }; 6781fa9e4066Sahrens 67824445fffbSMatthew Ahrens static void 67834445fffbSMatthew Ahrens zfs_allow_log_destroy(void *arg) 67844445fffbSMatthew Ahrens { 67854445fffbSMatthew Ahrens char *poolname = arg; 67864445fffbSMatthew Ahrens strfree(poolname); 67874445fffbSMatthew Ahrens } 6788ec533521Sfr 6789fa9e4066Sahrens int 6790fa9e4066Sahrens _init(void) 6791fa9e4066Sahrens { 6792fa9e4066Sahrens int error; 6793fa9e4066Sahrens 6794a0965f35Sbonwick spa_init(FREAD | FWRITE); 6795a0965f35Sbonwick zfs_init(); 6796a0965f35Sbonwick zvol_init(); 67974445fffbSMatthew Ahrens zfs_ioctl_init(); 6798a0965f35Sbonwick 6799a0965f35Sbonwick if ((error = mod_install(&modlinkage)) != 0) { 6800a0965f35Sbonwick zvol_fini(); 6801a0965f35Sbonwick zfs_fini(); 6802a0965f35Sbonwick spa_fini(); 6803fa9e4066Sahrens return (error); 6804a0965f35Sbonwick } 6805fa9e4066Sahrens 6806ec533521Sfr tsd_create(&zfs_fsyncer_key, NULL); 68074445fffbSMatthew Ahrens tsd_create(&rrw_tsd_key, rrw_tsd_destroy); 68084445fffbSMatthew Ahrens tsd_create(&zfs_allow_log_key, zfs_allow_log_destroy); 6809ec533521Sfr 6810fa9e4066Sahrens error = ldi_ident_from_mod(&modlinkage, &zfs_li); 6811fa9e4066Sahrens ASSERT(error == 0); 6812ecd6cf80Smarks mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); 6813fa9e4066Sahrens 6814fa9e4066Sahrens return (0); 6815fa9e4066Sahrens } 6816fa9e4066Sahrens 6817fa9e4066Sahrens int 6818fa9e4066Sahrens _fini(void) 6819fa9e4066Sahrens { 6820fa9e4066Sahrens int error; 6821fa9e4066Sahrens 6822ea8dc4b6Seschrock if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) 6823be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 6824fa9e4066Sahrens 6825fa9e4066Sahrens if ((error = mod_remove(&modlinkage)) != 0) 6826fa9e4066Sahrens return (error); 6827fa9e4066Sahrens 6828fa9e4066Sahrens zvol_fini(); 6829fa9e4066Sahrens zfs_fini(); 6830fa9e4066Sahrens spa_fini(); 6831da6c28aaSamw if (zfs_nfsshare_inited) 6832ecd6cf80Smarks (void) ddi_modclose(nfs_mod); 6833da6c28aaSamw if (zfs_smbshare_inited) 6834da6c28aaSamw (void) ddi_modclose(smbsrv_mod); 6835da6c28aaSamw if (zfs_nfsshare_inited || zfs_smbshare_inited) 6836ecd6cf80Smarks (void) ddi_modclose(sharefs_mod); 6837fa9e4066Sahrens 6838ec533521Sfr tsd_destroy(&zfs_fsyncer_key); 6839fa9e4066Sahrens ldi_ident_release(zfs_li); 6840fa9e4066Sahrens zfs_li = NULL; 6841ecd6cf80Smarks mutex_destroy(&zfs_share_lock); 6842fa9e4066Sahrens 6843fa9e4066Sahrens return (error); 6844fa9e4066Sahrens } 6845fa9e4066Sahrens 6846fa9e4066Sahrens int 6847fa9e4066Sahrens _info(struct modinfo *modinfop) 6848fa9e4066Sahrens { 6849fa9e4066Sahrens return (mod_info(&modlinkage, modinfop)); 6850fa9e4066Sahrens } 6851