zfs_ioctl.c revision 168775
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22168404Spjd * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23168404Spjd * Use is subject to license terms. 24168404Spjd */ 25168404Spjd 26168404Spjd#pragma ident "%Z%%M% %I% %E% SMI" 27168404Spjd 28168404Spjd#include <sys/param.h> 29168404Spjd#include <sys/systm.h> 30168404Spjd#include <sys/conf.h> 31168404Spjd#include <sys/kernel.h> 32168404Spjd#include <sys/lock.h> 33168404Spjd#include <sys/malloc.h> 34168404Spjd#include <sys/mutex.h> 35168404Spjd#include <sys/proc.h> 36168404Spjd#include <sys/errno.h> 37168404Spjd#include <sys/uio.h> 38168404Spjd#include <sys/file.h> 39168404Spjd#include <sys/kmem.h> 40168404Spjd#include <sys/conf.h> 41168404Spjd#include <sys/cmn_err.h> 42168404Spjd#include <sys/stat.h> 43168404Spjd#include <sys/zfs_ioctl.h> 44168404Spjd#include <sys/zap.h> 45168404Spjd#include <sys/spa.h> 46168404Spjd#include <sys/spa_impl.h> 47168404Spjd#include <sys/vdev.h> 48168404Spjd#include <sys/vdev_impl.h> 49168404Spjd#include <sys/dmu.h> 50168404Spjd#include <sys/dsl_dir.h> 51168404Spjd#include <sys/dsl_dataset.h> 52168404Spjd#include <sys/dsl_prop.h> 53168404Spjd#include <sys/nvpair.h> 54168404Spjd#include <sys/mount.h> 55168404Spjd#include <sys/taskqueue.h> 56168404Spjd#include <sys/sdt.h> 57168404Spjd#include <sys/varargs.h> 58168404Spjd#include <sys/fs/zfs.h> 59168404Spjd#include <sys/zfs_ctldir.h> 60168404Spjd#include <sys/zvol.h> 61168404Spjd 62168404Spjd#include "zfs_namecheck.h" 63168404Spjd#include "zfs_prop.h" 64168404Spjd 65168404SpjdCTASSERT(sizeof(zfs_cmd_t) <= PAGE_SIZE); 66168404Spjd 67168404Spjdstatic struct cdev *zfsdev; 68168404Spjd 69168404Spjdextern void zfs_init(void); 70168404Spjdextern void zfs_fini(void); 71168404Spjd 72168404Spjdtypedef int zfs_ioc_func_t(zfs_cmd_t *); 73168404Spjdtypedef int zfs_secpolicy_func_t(const char *, cred_t *); 74168404Spjd 75168404Spjdtypedef struct zfs_ioc_vec { 76168404Spjd zfs_ioc_func_t *zvec_func; 77168404Spjd zfs_secpolicy_func_t *zvec_secpolicy; 78168404Spjd enum { 79168404Spjd no_name, 80168404Spjd pool_name, 81168404Spjd dataset_name 82168404Spjd } zvec_namecheck; 83168404Spjd} zfs_ioc_vec_t; 84168404Spjd 85168404Spjd/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ 86168404Spjdvoid 87168404Spjd__dprintf(const char *file, const char *func, int line, const char *fmt, ...) 88168404Spjd{ 89168404Spjd const char *newfile; 90168404Spjd char buf[256]; 91168404Spjd va_list adx; 92168404Spjd 93168404Spjd /* 94168404Spjd * Get rid of annoying "../common/" prefix to filename. 95168404Spjd */ 96168404Spjd newfile = strrchr(file, '/'); 97168404Spjd if (newfile != NULL) { 98168404Spjd newfile = newfile + 1; /* Get rid of leading / */ 99168404Spjd } else { 100168404Spjd newfile = file; 101168404Spjd } 102168404Spjd 103168404Spjd va_start(adx, fmt); 104168404Spjd (void) vsnprintf(buf, sizeof (buf), fmt, adx); 105168404Spjd va_end(adx); 106168404Spjd 107168404Spjd /* 108168404Spjd * To get this data, use the zfs-dprintf probe as so: 109168404Spjd * dtrace -q -n 'zfs-dprintf \ 110168404Spjd * /stringof(arg0) == "dbuf.c"/ \ 111168404Spjd * {printf("%s: %s", stringof(arg1), stringof(arg3))}' 112168404Spjd * arg0 = file name 113168404Spjd * arg1 = function name 114168404Spjd * arg2 = line number 115168404Spjd * arg3 = message 116168404Spjd */ 117168404Spjd DTRACE_PROBE4(zfs__dprintf, 118168404Spjd char *, newfile, char *, func, int, line, char *, buf); 119168404Spjd} 120168404Spjd 121168404Spjd/* 122168404Spjd * Policy for top-level read operations (list pools). Requires no privileges, 123168404Spjd * and can be used in the local zone, as there is no associated dataset. 124168404Spjd */ 125168404Spjd/* ARGSUSED */ 126168404Spjdstatic int 127168404Spjdzfs_secpolicy_none(const char *unused1, cred_t *cr) 128168404Spjd{ 129168404Spjd return (0); 130168404Spjd} 131168404Spjd 132168404Spjd/* 133168404Spjd * Policy for dataset read operations (list children, get statistics). Requires 134168404Spjd * no privileges, but must be visible in the local zone. 135168404Spjd */ 136168404Spjd/* ARGSUSED */ 137168404Spjdstatic int 138168404Spjdzfs_secpolicy_read(const char *dataset, cred_t *cr) 139168404Spjd{ 140168404Spjd if (INGLOBALZONE(curproc) || 141168404Spjd zone_dataset_visible(dataset, NULL)) 142168404Spjd return (0); 143168404Spjd 144168404Spjd return (ENOENT); 145168404Spjd} 146168404Spjd 147168404Spjdstatic int 148168404Spjdzfs_dozonecheck(const char *dataset, cred_t *cr) 149168404Spjd{ 150168404Spjd uint64_t zoned; 151168404Spjd int writable = 1; 152168404Spjd 153168404Spjd /* 154168404Spjd * The dataset must be visible by this zone -- check this first 155168404Spjd * so they don't see EPERM on something they shouldn't know about. 156168404Spjd */ 157168404Spjd if (!INGLOBALZONE(curproc) && 158168404Spjd !zone_dataset_visible(dataset, &writable)) 159168404Spjd return (ENOENT); 160168404Spjd 161168404Spjd if (dsl_prop_get_integer(dataset, "jailed", &zoned, NULL)) 162168404Spjd return (ENOENT); 163168404Spjd 164168404Spjd if (INGLOBALZONE(curproc)) { 165168404Spjd /* 166168404Spjd * If the fs is zoned, only root can access it from the 167168404Spjd * global zone. 168168404Spjd */ 169168404Spjd if (secpolicy_zfs(cr) && zoned) 170168404Spjd return (EPERM); 171168404Spjd } else { 172168404Spjd /* 173168404Spjd * If we are in a local zone, the 'zoned' property must be set. 174168404Spjd */ 175168404Spjd if (!zoned) 176168404Spjd return (EPERM); 177168404Spjd 178168404Spjd /* must be writable by this zone */ 179168404Spjd if (!writable) 180168404Spjd return (EPERM); 181168404Spjd } 182168404Spjd return (0); 183168404Spjd} 184168404Spjd 185168404Spjd/* 186168404Spjd * Policy for dataset write operations (create children, set properties, etc). 187168404Spjd * Requires SYS_MOUNT privilege, and must be writable in the local zone. 188168404Spjd */ 189168404Spjdint 190168404Spjdzfs_secpolicy_write(const char *dataset, cred_t *cr) 191168404Spjd{ 192168404Spjd int error; 193168404Spjd 194168404Spjd if (error = zfs_dozonecheck(dataset, cr)) 195168404Spjd return (error); 196168404Spjd 197168404Spjd return (secpolicy_zfs(cr)); 198168404Spjd} 199168404Spjd 200168404Spjd/* 201168404Spjd * Policy for operations that want to write a dataset's parent: 202168404Spjd * create, destroy, snapshot, clone, restore. 203168404Spjd */ 204168404Spjdstatic int 205168404Spjdzfs_secpolicy_parent(const char *dataset, cred_t *cr) 206168404Spjd{ 207168404Spjd char parentname[MAXNAMELEN]; 208168404Spjd char *cp; 209168404Spjd 210168404Spjd /* 211168404Spjd * Remove the @bla or /bla from the end of the name to get the parent. 212168404Spjd */ 213168404Spjd (void) strncpy(parentname, dataset, sizeof (parentname)); 214168404Spjd cp = strrchr(parentname, '@'); 215168404Spjd if (cp != NULL) { 216168404Spjd cp[0] = '\0'; 217168404Spjd } else { 218168404Spjd cp = strrchr(parentname, '/'); 219168404Spjd if (cp == NULL) 220168404Spjd return (ENOENT); 221168404Spjd cp[0] = '\0'; 222168404Spjd 223168404Spjd } 224168404Spjd 225168404Spjd return (zfs_secpolicy_write(parentname, cr)); 226168404Spjd} 227168404Spjd 228168404Spjd/* 229168404Spjd * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires 230168404Spjd * SYS_CONFIG privilege, which is not available in a local zone. 231168404Spjd */ 232168404Spjd/* ARGSUSED */ 233168404Spjdstatic int 234168404Spjdzfs_secpolicy_config(const char *unused, cred_t *cr) 235168404Spjd{ 236168404Spjd if (secpolicy_sys_config(cr, B_FALSE) != 0) 237168404Spjd return (EPERM); 238168404Spjd 239168404Spjd return (0); 240168404Spjd} 241168404Spjd 242168404Spjd/* 243168404Spjd * Policy for fault injection. Requires all privileges. 244168404Spjd */ 245168404Spjd/* ARGSUSED */ 246168404Spjdstatic int 247168404Spjdzfs_secpolicy_inject(const char *unused, cred_t *cr) 248168404Spjd{ 249168404Spjd return (secpolicy_zinject(cr)); 250168404Spjd} 251168404Spjd 252168404Spjd/* 253168404Spjd * Policy for dataset backup operations (sendbackup). 254168404Spjd * Requires SYS_MOUNT privilege, and must be writable in the local zone. 255168404Spjd */ 256168404Spjdstatic int 257168404Spjdzfs_secpolicy_operator(const char *dataset, cred_t *cr) 258168404Spjd{ 259168404Spjd int writable = 1; 260168404Spjd 261168404Spjd if (!INGLOBALZONE(curproc) && !zone_dataset_visible(dataset, &writable)) 262168404Spjd return (ENOENT); 263168404Spjd if (secpolicy_zfs(cr) != 0 && !groupmember(GID_OPERATOR, cr)) 264168404Spjd return (EPERM); 265168404Spjd return (0); 266168404Spjd} 267168404Spjd 268168404Spjd/* 269168404Spjd * Returns the nvlist as specified by the user in the zfs_cmd_t. 270168404Spjd */ 271168404Spjdstatic int 272168404Spjdget_nvlist(zfs_cmd_t *zc, nvlist_t **nvp) 273168404Spjd{ 274168404Spjd char *packed; 275168404Spjd size_t size; 276168404Spjd int error; 277168404Spjd nvlist_t *config = NULL; 278168404Spjd 279168404Spjd /* 280168404Spjd * Read in and unpack the user-supplied nvlist. 281168404Spjd */ 282168404Spjd if ((size = zc->zc_nvlist_src_size) == 0) 283168404Spjd return (EINVAL); 284168404Spjd 285168404Spjd packed = kmem_alloc(size, KM_SLEEP); 286168404Spjd 287168404Spjd if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed, 288168404Spjd size)) != 0) { 289168404Spjd kmem_free(packed, size); 290168404Spjd return (error); 291168404Spjd } 292168404Spjd 293168404Spjd if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) { 294168404Spjd kmem_free(packed, size); 295168404Spjd return (error); 296168404Spjd } 297168404Spjd 298168404Spjd kmem_free(packed, size); 299168404Spjd 300168404Spjd *nvp = config; 301168404Spjd return (0); 302168404Spjd} 303168404Spjd 304168404Spjdstatic int 305168404Spjdput_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 306168404Spjd{ 307168404Spjd char *packed = NULL; 308168404Spjd size_t size; 309168404Spjd int error; 310168404Spjd 311168404Spjd VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 312168404Spjd 313168404Spjd if (size > zc->zc_nvlist_dst_size) { 314168404Spjd /* 315168404Spjd * Solaris returns ENOMEM here, because even if an error is 316168404Spjd * returned from an ioctl(2), new zc_nvlist_dst_size will be 317168404Spjd * passed to the userland. This is not the case for FreeBSD. 318168404Spjd * We need to return 0, so the kernel will copy the 319168404Spjd * zc_nvlist_dst_size back and the userland can discover that a 320168404Spjd * bigger buffer is needed. 321168404Spjd */ 322168404Spjd error = 0; 323168404Spjd } else { 324168404Spjd VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 325168404Spjd KM_SLEEP) == 0); 326168404Spjd error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, 327168404Spjd size); 328168404Spjd kmem_free(packed, size); 329168404Spjd } 330168404Spjd 331168404Spjd zc->zc_nvlist_dst_size = size; 332168404Spjd return (error); 333168404Spjd} 334168404Spjd 335168404Spjdstatic int 336168404Spjdzfs_ioc_pool_create(zfs_cmd_t *zc) 337168404Spjd{ 338168404Spjd int error; 339168404Spjd nvlist_t *config; 340168404Spjd 341168404Spjd if ((error = get_nvlist(zc, &config)) != 0) 342168404Spjd return (error); 343168404Spjd 344168404Spjd error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ? 345168404Spjd NULL : zc->zc_value); 346168404Spjd 347168404Spjd nvlist_free(config); 348168404Spjd 349168404Spjd return (error); 350168404Spjd} 351168404Spjd 352168404Spjdstatic int 353168404Spjdzfs_ioc_pool_destroy(zfs_cmd_t *zc) 354168404Spjd{ 355168404Spjd return (spa_destroy(zc->zc_name)); 356168404Spjd} 357168404Spjd 358168404Spjdstatic int 359168404Spjdzfs_ioc_pool_import(zfs_cmd_t *zc) 360168404Spjd{ 361168404Spjd int error; 362168404Spjd nvlist_t *config; 363168404Spjd uint64_t guid; 364168404Spjd 365168404Spjd if ((error = get_nvlist(zc, &config)) != 0) 366168404Spjd return (error); 367168404Spjd 368168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || 369168404Spjd guid != zc->zc_guid) 370168404Spjd error = EINVAL; 371168404Spjd else 372168404Spjd error = spa_import(zc->zc_name, config, 373168404Spjd zc->zc_value[0] == '\0' ? NULL : zc->zc_value); 374168404Spjd 375168404Spjd nvlist_free(config); 376168404Spjd 377168404Spjd return (error); 378168404Spjd} 379168404Spjd 380168404Spjdstatic int 381168404Spjdzfs_ioc_pool_export(zfs_cmd_t *zc) 382168404Spjd{ 383168404Spjd return (spa_export(zc->zc_name, NULL)); 384168404Spjd} 385168404Spjd 386168404Spjdstatic int 387168404Spjdzfs_ioc_pool_configs(zfs_cmd_t *zc) 388168404Spjd{ 389168404Spjd nvlist_t *configs; 390168404Spjd int error; 391168404Spjd 392168404Spjd if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) 393168404Spjd return (EEXIST); 394168404Spjd 395168404Spjd error = put_nvlist(zc, configs); 396168404Spjd 397168404Spjd nvlist_free(configs); 398168404Spjd 399168404Spjd return (error); 400168404Spjd} 401168404Spjd 402168404Spjdstatic int 403168404Spjdzfs_ioc_pool_stats(zfs_cmd_t *zc) 404168404Spjd{ 405168404Spjd nvlist_t *config; 406168404Spjd int error; 407168404Spjd int ret = 0; 408168404Spjd 409168404Spjd error = spa_get_stats(zc->zc_name, &config, zc->zc_value, 410168404Spjd sizeof (zc->zc_value)); 411168404Spjd 412168404Spjd if (config != NULL) { 413168404Spjd ret = put_nvlist(zc, config); 414168404Spjd nvlist_free(config); 415168404Spjd 416168404Spjd /* 417168404Spjd * The config may be present even if 'error' is non-zero. 418168404Spjd * In this case we return success, and preserve the real errno 419168404Spjd * in 'zc_cookie'. 420168404Spjd */ 421168404Spjd zc->zc_cookie = error; 422168404Spjd } else { 423168404Spjd ret = error; 424168404Spjd } 425168404Spjd 426168404Spjd return (ret); 427168404Spjd} 428168404Spjd 429168404Spjd/* 430168404Spjd * Try to import the given pool, returning pool stats as appropriate so that 431168404Spjd * user land knows which devices are available and overall pool health. 432168404Spjd */ 433168404Spjdstatic int 434168404Spjdzfs_ioc_pool_tryimport(zfs_cmd_t *zc) 435168404Spjd{ 436168404Spjd nvlist_t *tryconfig, *config; 437168404Spjd int error; 438168404Spjd 439168404Spjd if ((error = get_nvlist(zc, &tryconfig)) != 0) 440168404Spjd return (error); 441168404Spjd 442168404Spjd config = spa_tryimport(tryconfig); 443168404Spjd 444168404Spjd nvlist_free(tryconfig); 445168404Spjd 446168404Spjd if (config == NULL) 447168404Spjd return (EINVAL); 448168404Spjd 449168404Spjd error = put_nvlist(zc, config); 450168404Spjd nvlist_free(config); 451168404Spjd 452168404Spjd return (error); 453168404Spjd} 454168404Spjd 455168404Spjdstatic int 456168404Spjdzfs_ioc_pool_scrub(zfs_cmd_t *zc) 457168404Spjd{ 458168404Spjd spa_t *spa; 459168404Spjd int error; 460168404Spjd 461168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 462168404Spjd return (error); 463168404Spjd 464168404Spjd error = spa_scrub(spa, zc->zc_cookie, B_FALSE); 465168404Spjd 466168404Spjd spa_close(spa, FTAG); 467168404Spjd 468168404Spjd return (error); 469168404Spjd} 470168404Spjd 471168404Spjdstatic int 472168404Spjdzfs_ioc_pool_freeze(zfs_cmd_t *zc) 473168404Spjd{ 474168404Spjd spa_t *spa; 475168404Spjd int error; 476168404Spjd 477168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 478168404Spjd if (error == 0) { 479168404Spjd spa_freeze(spa); 480168404Spjd spa_close(spa, FTAG); 481168404Spjd } 482168404Spjd return (error); 483168404Spjd} 484168404Spjd 485168404Spjdstatic int 486168404Spjdzfs_ioc_pool_upgrade(zfs_cmd_t *zc) 487168404Spjd{ 488168404Spjd spa_t *spa; 489168404Spjd int error; 490168404Spjd 491168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 492168404Spjd return (error); 493168404Spjd 494168404Spjd spa_upgrade(spa); 495168404Spjd 496168404Spjd spa_close(spa, FTAG); 497168404Spjd 498168404Spjd return (error); 499168404Spjd} 500168404Spjd 501168404Spjdstatic int 502168404Spjdzfs_ioc_pool_get_history(zfs_cmd_t *zc) 503168404Spjd{ 504168404Spjd spa_t *spa; 505168404Spjd char *hist_buf; 506168404Spjd uint64_t size; 507168404Spjd int error; 508168404Spjd 509168404Spjd if ((size = zc->zc_history_len) == 0) 510168404Spjd return (EINVAL); 511168404Spjd 512168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 513168404Spjd return (error); 514168404Spjd 515168404Spjd if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) { 516168404Spjd spa_close(spa, FTAG); 517168404Spjd return (ENOTSUP); 518168404Spjd } 519168404Spjd 520168404Spjd hist_buf = kmem_alloc(size, KM_SLEEP); 521168404Spjd if ((error = spa_history_get(spa, &zc->zc_history_offset, 522168404Spjd &zc->zc_history_len, hist_buf)) == 0) { 523168404Spjd error = xcopyout(hist_buf, (char *)(uintptr_t)zc->zc_history, 524168404Spjd zc->zc_history_len); 525168404Spjd } 526168404Spjd 527168404Spjd spa_close(spa, FTAG); 528168404Spjd kmem_free(hist_buf, size); 529168404Spjd return (error); 530168404Spjd} 531168404Spjd 532168404Spjdstatic int 533168404Spjdzfs_ioc_pool_log_history(zfs_cmd_t *zc) 534168404Spjd{ 535168404Spjd spa_t *spa; 536168404Spjd char *history_str = NULL; 537168404Spjd size_t size; 538168404Spjd int error; 539168404Spjd 540168404Spjd size = zc->zc_history_len; 541168404Spjd if (size == 0 || size > HIS_MAX_RECORD_LEN) 542168404Spjd return (EINVAL); 543168404Spjd 544168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 545168404Spjd return (error); 546168404Spjd 547168404Spjd if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) { 548168404Spjd spa_close(spa, FTAG); 549168404Spjd return (ENOTSUP); 550168404Spjd } 551168404Spjd 552168404Spjd /* add one for the NULL delimiter */ 553168404Spjd size++; 554168404Spjd history_str = kmem_alloc(size, KM_SLEEP); 555168404Spjd if ((error = xcopyin((void *)(uintptr_t)zc->zc_history, history_str, 556168404Spjd size)) != 0) { 557168404Spjd spa_close(spa, FTAG); 558168404Spjd kmem_free(history_str, size); 559168404Spjd return (error); 560168404Spjd } 561168404Spjd history_str[size - 1] = '\0'; 562168404Spjd 563168404Spjd error = spa_history_log(spa, history_str, zc->zc_history_offset); 564168404Spjd 565168404Spjd spa_close(spa, FTAG); 566168404Spjd kmem_free(history_str, size); 567168404Spjd 568168404Spjd return (error); 569168404Spjd} 570168404Spjd 571168404Spjdstatic int 572168404Spjdzfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) 573168404Spjd{ 574168404Spjd int error; 575168404Spjd 576168404Spjd if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) 577168404Spjd return (error); 578168404Spjd 579168404Spjd return (0); 580168404Spjd} 581168404Spjd 582168404Spjdstatic int 583168404Spjdzfs_ioc_obj_to_path(zfs_cmd_t *zc) 584168404Spjd{ 585168404Spjd objset_t *osp; 586168404Spjd int error; 587168404Spjd 588168404Spjd if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, 589168404Spjd DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) 590168404Spjd return (error); 591168404Spjd 592168404Spjd error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, 593168404Spjd sizeof (zc->zc_value)); 594168404Spjd dmu_objset_close(osp); 595168404Spjd 596168404Spjd return (error); 597168404Spjd} 598168404Spjd 599168404Spjdstatic int 600168404Spjdzfs_ioc_vdev_add(zfs_cmd_t *zc) 601168404Spjd{ 602168404Spjd spa_t *spa; 603168404Spjd int error; 604168404Spjd nvlist_t *config; 605168404Spjd 606168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 607168404Spjd if (error != 0) 608168404Spjd return (error); 609168404Spjd 610168404Spjd /* 611168404Spjd * A root pool with concatenated devices is not supported. 612168404Spjd * Thus, can not add a device to a root pool with one device. 613168404Spjd */ 614168404Spjd if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) { 615168404Spjd spa_close(spa, FTAG); 616168404Spjd return (EDOM); 617168404Spjd } 618168404Spjd 619168404Spjd if ((error = get_nvlist(zc, &config)) == 0) { 620168404Spjd error = spa_vdev_add(spa, config); 621168404Spjd nvlist_free(config); 622168404Spjd } 623168404Spjd 624168404Spjd spa_close(spa, FTAG); 625168404Spjd return (error); 626168404Spjd} 627168404Spjd 628168404Spjdstatic int 629168404Spjdzfs_ioc_vdev_remove(zfs_cmd_t *zc) 630168404Spjd{ 631168404Spjd spa_t *spa; 632168404Spjd int error; 633168404Spjd 634168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 635168404Spjd if (error != 0) 636168404Spjd return (error); 637168404Spjd error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); 638168404Spjd spa_close(spa, FTAG); 639168404Spjd return (error); 640168404Spjd} 641168404Spjd 642168404Spjdstatic int 643168404Spjdzfs_ioc_vdev_online(zfs_cmd_t *zc) 644168404Spjd{ 645168404Spjd spa_t *spa; 646168404Spjd int error; 647168404Spjd 648168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 649168404Spjd return (error); 650168404Spjd error = vdev_online(spa, zc->zc_guid); 651168404Spjd spa_close(spa, FTAG); 652168404Spjd return (error); 653168404Spjd} 654168404Spjd 655168404Spjdstatic int 656168404Spjdzfs_ioc_vdev_offline(zfs_cmd_t *zc) 657168404Spjd{ 658168404Spjd spa_t *spa; 659168404Spjd int istmp = zc->zc_cookie; 660168404Spjd int error; 661168404Spjd 662168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 663168404Spjd return (error); 664168404Spjd error = vdev_offline(spa, zc->zc_guid, istmp); 665168404Spjd spa_close(spa, FTAG); 666168404Spjd return (error); 667168404Spjd} 668168404Spjd 669168404Spjdstatic int 670168404Spjdzfs_ioc_vdev_attach(zfs_cmd_t *zc) 671168404Spjd{ 672168404Spjd spa_t *spa; 673168404Spjd int replacing = zc->zc_cookie; 674168404Spjd nvlist_t *config; 675168404Spjd int error; 676168404Spjd 677168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 678168404Spjd return (error); 679168404Spjd 680168404Spjd if ((error = get_nvlist(zc, &config)) == 0) { 681168404Spjd error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); 682168404Spjd nvlist_free(config); 683168404Spjd } 684168404Spjd 685168404Spjd spa_close(spa, FTAG); 686168404Spjd return (error); 687168404Spjd} 688168404Spjd 689168404Spjdstatic int 690168404Spjdzfs_ioc_vdev_detach(zfs_cmd_t *zc) 691168404Spjd{ 692168404Spjd spa_t *spa; 693168404Spjd int error; 694168404Spjd 695168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 696168404Spjd return (error); 697168404Spjd 698168404Spjd error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); 699168404Spjd 700168404Spjd spa_close(spa, FTAG); 701168404Spjd return (error); 702168404Spjd} 703168404Spjd 704168404Spjdstatic int 705168404Spjdzfs_ioc_vdev_setpath(zfs_cmd_t *zc) 706168404Spjd{ 707168404Spjd spa_t *spa; 708168404Spjd char *path = zc->zc_value; 709168404Spjd uint64_t guid = zc->zc_guid; 710168404Spjd int error; 711168404Spjd 712168404Spjd error = spa_open(zc->zc_name, &spa, FTAG); 713168404Spjd if (error != 0) 714168404Spjd return (error); 715168404Spjd 716168404Spjd error = spa_vdev_setpath(spa, guid, path); 717168404Spjd spa_close(spa, FTAG); 718168404Spjd return (error); 719168404Spjd} 720168404Spjd 721168404Spjdstatic int 722168404Spjdzfs_ioc_objset_stats(zfs_cmd_t *zc) 723168404Spjd{ 724168404Spjd objset_t *os = NULL; 725168404Spjd int error; 726168404Spjd nvlist_t *nv; 727168404Spjd 728168404Spjdretry: 729168404Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 730168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &os); 731168404Spjd if (error != 0) { 732168404Spjd /* 733168404Spjd * This is ugly: dmu_objset_open() can return EBUSY if 734168404Spjd * the objset is held exclusively. Fortunately this hold is 735168404Spjd * only for a short while, so we retry here. 736168404Spjd * This avoids user code having to handle EBUSY, 737168404Spjd * for example for a "zfs list". 738168404Spjd */ 739168404Spjd if (error == EBUSY) { 740168404Spjd delay(1); 741168404Spjd goto retry; 742168404Spjd } 743168404Spjd return (error); 744168404Spjd } 745168404Spjd 746168404Spjd dmu_objset_fast_stat(os, &zc->zc_objset_stats); 747168404Spjd 748168404Spjd if (zc->zc_nvlist_dst != 0 && 749168404Spjd (error = dsl_prop_get_all(os, &nv)) == 0) { 750168404Spjd dmu_objset_stats(os, nv); 751168404Spjd /* 752168404Spjd * NB: zvol_get_stats() will read the objset contents, 753168404Spjd * which we aren't supposed to do with a 754168404Spjd * DS_MODE_STANDARD open, because it could be 755168404Spjd * inconsistent. So this is a bit of a workaround... 756168404Spjd */ 757168404Spjd if (!zc->zc_objset_stats.dds_inconsistent && 758168404Spjd dmu_objset_type(os) == DMU_OST_ZVOL) 759168404Spjd VERIFY(zvol_get_stats(os, nv) == 0); 760168404Spjd error = put_nvlist(zc, nv); 761168404Spjd nvlist_free(nv); 762168404Spjd } 763168404Spjd 764168404Spjd spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); 765168404Spjd 766168404Spjd dmu_objset_close(os); 767168404Spjd if (error == ENOMEM) 768168404Spjd error = 0; 769168404Spjd return (error); 770168404Spjd} 771168404Spjd 772168404Spjdstatic int 773168404Spjdzfs_ioc_dataset_list_next(zfs_cmd_t *zc) 774168404Spjd{ 775168404Spjd objset_t *os; 776168404Spjd int error; 777168404Spjd char *p; 778168404Spjd 779168404Spjdretry: 780168404Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 781168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &os); 782168404Spjd if (error != 0) { 783168404Spjd /* 784168404Spjd * This is ugly: dmu_objset_open() can return EBUSY if 785168404Spjd * the objset is held exclusively. Fortunately this hold is 786168404Spjd * only for a short while, so we retry here. 787168404Spjd * This avoids user code having to handle EBUSY, 788168404Spjd * for example for a "zfs list". 789168404Spjd */ 790168404Spjd if (error == EBUSY) { 791168404Spjd delay(1); 792168404Spjd goto retry; 793168404Spjd } 794168404Spjd if (error == ENOENT) 795168404Spjd error = ESRCH; 796168404Spjd return (error); 797168404Spjd } 798168404Spjd 799168404Spjd p = strrchr(zc->zc_name, '/'); 800168404Spjd if (p == NULL || p[1] != '\0') 801168404Spjd (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); 802168404Spjd p = zc->zc_name + strlen(zc->zc_name); 803168404Spjd 804168404Spjd do { 805168404Spjd error = dmu_dir_list_next(os, 806168404Spjd sizeof (zc->zc_name) - (p - zc->zc_name), p, 807168404Spjd NULL, &zc->zc_cookie); 808168404Spjd if (error == ENOENT) 809168404Spjd error = ESRCH; 810168404Spjd } while (error == 0 && !INGLOBALZONE(curproc) && 811168404Spjd !zone_dataset_visible(zc->zc_name, NULL)); 812168404Spjd 813168404Spjd /* 814168404Spjd * If it's a hidden dataset (ie. with a '$' in its name), don't 815168404Spjd * try to get stats for it. Userland will skip over it. 816168404Spjd */ 817168404Spjd if (error == 0 && strchr(zc->zc_name, '$') == NULL) 818168404Spjd error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 819168404Spjd 820168404Spjd dmu_objset_close(os); 821168404Spjd return (error); 822168404Spjd} 823168404Spjd 824168404Spjdstatic int 825168404Spjdzfs_ioc_snapshot_list_next(zfs_cmd_t *zc) 826168404Spjd{ 827168404Spjd objset_t *os; 828168404Spjd int error; 829168404Spjd 830168404Spjdretry: 831168404Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 832168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &os); 833168404Spjd if (error != 0) { 834168404Spjd /* 835168404Spjd * This is ugly: dmu_objset_open() can return EBUSY if 836168404Spjd * the objset is held exclusively. Fortunately this hold is 837168404Spjd * only for a short while, so we retry here. 838168404Spjd * This avoids user code having to handle EBUSY, 839168404Spjd * for example for a "zfs list". 840168404Spjd */ 841168404Spjd if (error == EBUSY) { 842168404Spjd delay(1); 843168404Spjd goto retry; 844168404Spjd } 845168404Spjd if (error == ENOENT) 846168404Spjd error = ESRCH; 847168404Spjd return (error); 848168404Spjd } 849168404Spjd 850168404Spjd /* 851168404Spjd * A dataset name of maximum length cannot have any snapshots, 852168404Spjd * so exit immediately. 853168404Spjd */ 854168404Spjd if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { 855168404Spjd dmu_objset_close(os); 856168404Spjd return (ESRCH); 857168404Spjd } 858168404Spjd 859168404Spjd error = dmu_snapshot_list_next(os, 860168404Spjd sizeof (zc->zc_name) - strlen(zc->zc_name), 861168404Spjd zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); 862168404Spjd if (error == ENOENT) 863168404Spjd error = ESRCH; 864168404Spjd 865168404Spjd if (error == 0) 866168404Spjd error = zfs_ioc_objset_stats(zc); /* fill in the stats */ 867168404Spjd 868168404Spjd dmu_objset_close(os); 869168404Spjd return (error); 870168404Spjd} 871168404Spjd 872168404Spjdstatic int 873168404Spjdzfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) 874168404Spjd{ 875168404Spjd nvpair_t *elem; 876168404Spjd int error; 877168404Spjd const char *propname; 878168404Spjd zfs_prop_t prop; 879168404Spjd uint64_t intval; 880168404Spjd char *strval; 881168404Spjd char buf[MAXNAMELEN]; 882168404Spjd const char *p; 883168404Spjd spa_t *spa; 884168404Spjd 885168404Spjd elem = NULL; 886168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 887168404Spjd propname = nvpair_name(elem); 888168404Spjd 889168404Spjd if ((prop = zfs_name_to_prop(propname)) == 890168404Spjd ZFS_PROP_INVAL) { 891168404Spjd /* 892168404Spjd * If this is a user-defined property, it must be a 893168404Spjd * string, and there is no further validation to do. 894168404Spjd */ 895168404Spjd if (!zfs_prop_user(propname) || 896168404Spjd nvpair_type(elem) != DATA_TYPE_STRING) 897168404Spjd return (EINVAL); 898168404Spjd 899168404Spjd VERIFY(nvpair_value_string(elem, &strval) == 0); 900168404Spjd error = dsl_prop_set(name, propname, 1, 901168404Spjd strlen(strval) + 1, strval); 902168404Spjd if (error == 0) 903168404Spjd continue; 904168404Spjd else 905168404Spjd return (error); 906168404Spjd } 907168404Spjd 908168404Spjd /* 909168404Spjd * Check permissions for special properties. 910168404Spjd */ 911168404Spjd switch (prop) { 912168404Spjd case ZFS_PROP_ZONED: 913168404Spjd /* 914168404Spjd * Disallow setting of 'zoned' from within a local zone. 915168404Spjd */ 916168404Spjd if (!INGLOBALZONE(curproc)) 917168404Spjd return (EPERM); 918168404Spjd break; 919168404Spjd 920168404Spjd case ZFS_PROP_QUOTA: 921168404Spjd if (error = zfs_dozonecheck(name, cr)) 922168404Spjd return (error); 923168404Spjd 924168404Spjd if (!INGLOBALZONE(curproc)) { 925168404Spjd uint64_t zoned; 926168404Spjd char setpoint[MAXNAMELEN]; 927168404Spjd int dslen; 928168404Spjd /* 929168404Spjd * Unprivileged users are allowed to modify the 930168404Spjd * quota on things *under* (ie. contained by) 931168404Spjd * the thing they own. 932168404Spjd */ 933168404Spjd if (dsl_prop_get_integer(name, "jailed", &zoned, 934168404Spjd setpoint)) 935168404Spjd return (EPERM); 936168404Spjd if (!zoned) /* this shouldn't happen */ 937168404Spjd return (EPERM); 938168404Spjd dslen = strlen(name); 939168404Spjd if (dslen <= strlen(setpoint)) 940168404Spjd return (EPERM); 941168404Spjd } 942168404Spjd break; 943168404Spjd 944168404Spjd case ZFS_PROP_COMPRESSION: 945168404Spjd /* 946168404Spjd * If the user specified gzip compression, make sure 947168404Spjd * the SPA supports it. We ignore any errors here since 948168404Spjd * we'll catch them later. 949168404Spjd */ 950168404Spjd if (nvpair_type(elem) == DATA_TYPE_UINT64 && 951168404Spjd nvpair_value_uint64(elem, &intval) == 0 && 952168404Spjd intval >= ZIO_COMPRESS_GZIP_1 && 953168404Spjd intval <= ZIO_COMPRESS_GZIP_9) { 954168404Spjd if ((p = strchr(name, '/')) == NULL) { 955168404Spjd p = name; 956168404Spjd } else { 957168404Spjd bcopy(name, buf, p - name); 958168404Spjd buf[p - name] = '\0'; 959168404Spjd p = buf; 960168404Spjd } 961168404Spjd 962168404Spjd if (spa_open(p, &spa, FTAG) == 0) { 963168404Spjd if (spa_version(spa) < 964168404Spjd ZFS_VERSION_GZIP_COMPRESSION) { 965168404Spjd spa_close(spa, FTAG); 966168404Spjd return (ENOTSUP); 967168404Spjd } 968168404Spjd 969168404Spjd spa_close(spa, FTAG); 970168404Spjd } 971168404Spjd } 972168404Spjd break; 973168404Spjd } 974168404Spjd 975168404Spjd switch (prop) { 976168404Spjd case ZFS_PROP_QUOTA: 977168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 978168404Spjd (error = dsl_dir_set_quota(name, 979168404Spjd intval)) != 0) 980168404Spjd return (error); 981168404Spjd break; 982168404Spjd 983168404Spjd case ZFS_PROP_RESERVATION: 984168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 985168404Spjd (error = dsl_dir_set_reservation(name, 986168404Spjd intval)) != 0) 987168404Spjd return (error); 988168404Spjd break; 989168404Spjd 990168404Spjd case ZFS_PROP_VOLSIZE: 991168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 992168404Spjd (error = zvol_set_volsize(name, dev, 993168404Spjd intval)) != 0) 994168404Spjd return (error); 995168404Spjd break; 996168404Spjd 997168404Spjd case ZFS_PROP_VOLBLOCKSIZE: 998168404Spjd if ((error = nvpair_value_uint64(elem, &intval)) != 0 || 999168404Spjd (error = zvol_set_volblocksize(name, 1000168404Spjd intval)) != 0) 1001168404Spjd return (error); 1002168404Spjd break; 1003168404Spjd 1004168404Spjd default: 1005168404Spjd if (nvpair_type(elem) == DATA_TYPE_STRING) { 1006168404Spjd if (zfs_prop_get_type(prop) != 1007168404Spjd prop_type_string) 1008168404Spjd return (EINVAL); 1009168404Spjd VERIFY(nvpair_value_string(elem, &strval) == 0); 1010168404Spjd if ((error = dsl_prop_set(name, 1011168404Spjd nvpair_name(elem), 1, strlen(strval) + 1, 1012168404Spjd strval)) != 0) 1013168404Spjd return (error); 1014168404Spjd } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { 1015168404Spjd const char *unused; 1016168404Spjd 1017168404Spjd VERIFY(nvpair_value_uint64(elem, &intval) == 0); 1018168404Spjd 1019168404Spjd switch (zfs_prop_get_type(prop)) { 1020168404Spjd case prop_type_number: 1021168404Spjd break; 1022168404Spjd case prop_type_boolean: 1023168404Spjd if (intval > 1) 1024168404Spjd return (EINVAL); 1025168404Spjd break; 1026168404Spjd case prop_type_string: 1027168404Spjd return (EINVAL); 1028168404Spjd case prop_type_index: 1029168404Spjd if (zfs_prop_index_to_string(prop, 1030168404Spjd intval, &unused) != 0) 1031168404Spjd return (EINVAL); 1032168404Spjd break; 1033168404Spjd default: 1034168404Spjd cmn_err(CE_PANIC, "unknown property " 1035168404Spjd "type"); 1036168404Spjd break; 1037168404Spjd } 1038168404Spjd 1039168404Spjd if ((error = dsl_prop_set(name, propname, 1040168404Spjd 8, 1, &intval)) != 0) 1041168404Spjd return (error); 1042168404Spjd } else { 1043168404Spjd return (EINVAL); 1044168404Spjd } 1045168404Spjd break; 1046168404Spjd } 1047168404Spjd } 1048168404Spjd 1049168404Spjd return (0); 1050168404Spjd} 1051168404Spjd 1052168404Spjdstatic int 1053168404Spjdzfs_ioc_set_prop(zfs_cmd_t *zc) 1054168404Spjd{ 1055168404Spjd nvlist_t *nvl; 1056168404Spjd int error; 1057168404Spjd zfs_prop_t prop; 1058168404Spjd 1059168404Spjd /* 1060168404Spjd * If zc_value is set, then this is an attempt to inherit a value. 1061168404Spjd * Otherwise, zc_nvlist refers to a list of properties to set. 1062168404Spjd */ 1063168404Spjd if (zc->zc_value[0] != '\0') { 1064168404Spjd if (!zfs_prop_user(zc->zc_value) && 1065168404Spjd ((prop = zfs_name_to_prop(zc->zc_value)) == 1066168404Spjd ZFS_PROP_INVAL || 1067168404Spjd !zfs_prop_inheritable(prop))) 1068168404Spjd return (EINVAL); 1069168404Spjd 1070168404Spjd return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); 1071168404Spjd } 1072168404Spjd 1073168404Spjd if ((error = get_nvlist(zc, &nvl)) != 0) 1074168404Spjd return (error); 1075168404Spjd 1076168404Spjd error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev, 1077168404Spjd (cred_t *)(uintptr_t)zc->zc_cred, nvl); 1078168404Spjd nvlist_free(nvl); 1079168404Spjd return (error); 1080168404Spjd} 1081168404Spjd 1082168404Spjdstatic int 1083168404Spjdzfs_ioc_pool_props_set(zfs_cmd_t *zc) 1084168404Spjd{ 1085168404Spjd nvlist_t *nvl; 1086168404Spjd int error, reset_bootfs = 0; 1087168404Spjd uint64_t objnum; 1088168404Spjd zpool_prop_t prop; 1089168404Spjd nvpair_t *elem; 1090168404Spjd char *propname, *strval; 1091168404Spjd spa_t *spa; 1092168404Spjd vdev_t *rvdev; 1093168404Spjd char *vdev_type; 1094168404Spjd objset_t *os; 1095168404Spjd 1096168404Spjd if ((error = get_nvlist(zc, &nvl)) != 0) 1097168404Spjd return (error); 1098168404Spjd 1099168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { 1100168404Spjd nvlist_free(nvl); 1101168404Spjd return (error); 1102168404Spjd } 1103168404Spjd 1104168404Spjd if (spa_version(spa) < ZFS_VERSION_BOOTFS) { 1105168404Spjd nvlist_free(nvl); 1106168404Spjd spa_close(spa, FTAG); 1107168404Spjd return (ENOTSUP); 1108168404Spjd } 1109168404Spjd 1110168404Spjd elem = NULL; 1111168404Spjd while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { 1112168404Spjd 1113168404Spjd propname = nvpair_name(elem); 1114168404Spjd 1115168404Spjd if ((prop = zpool_name_to_prop(propname)) == 1116168404Spjd ZFS_PROP_INVAL) { 1117168404Spjd nvlist_free(nvl); 1118168404Spjd spa_close(spa, FTAG); 1119168404Spjd return (EINVAL); 1120168404Spjd } 1121168404Spjd 1122168404Spjd switch (prop) { 1123168404Spjd case ZFS_PROP_BOOTFS: 1124168404Spjd /* 1125168404Spjd * A bootable filesystem can not be on a RAIDZ pool 1126168404Spjd * nor a striped pool with more than 1 device. 1127168404Spjd */ 1128168404Spjd rvdev = spa->spa_root_vdev; 1129168404Spjd vdev_type = 1130168404Spjd rvdev->vdev_child[0]->vdev_ops->vdev_op_type; 1131168404Spjd if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 || 1132168404Spjd (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 && 1133168404Spjd rvdev->vdev_children > 1)) { 1134168404Spjd error = ENOTSUP; 1135168404Spjd break; 1136168404Spjd } 1137168404Spjd 1138168404Spjd reset_bootfs = 1; 1139168404Spjd 1140168404Spjd VERIFY(nvpair_value_string(elem, &strval) == 0); 1141168404Spjd if (strval == NULL || strval[0] == '\0') { 1142168404Spjd objnum = 1143168404Spjd zfs_prop_default_numeric(ZFS_PROP_BOOTFS); 1144168404Spjd break; 1145168404Spjd } 1146168404Spjd 1147168404Spjd if (error = dmu_objset_open(strval, DMU_OST_ZFS, 1148168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &os)) 1149168404Spjd break; 1150168404Spjd objnum = dmu_objset_id(os); 1151168404Spjd dmu_objset_close(os); 1152168404Spjd break; 1153168404Spjd 1154168404Spjd default: 1155168404Spjd error = EINVAL; 1156168404Spjd } 1157168404Spjd 1158168404Spjd if (error) 1159168404Spjd break; 1160168404Spjd } 1161168404Spjd if (error == 0) { 1162168404Spjd if (reset_bootfs) { 1163168404Spjd VERIFY(nvlist_remove(nvl, 1164168404Spjd zpool_prop_to_name(ZFS_PROP_BOOTFS), 1165168404Spjd DATA_TYPE_STRING) == 0); 1166168404Spjd VERIFY(nvlist_add_uint64(nvl, 1167168404Spjd zpool_prop_to_name(ZFS_PROP_BOOTFS), objnum) == 0); 1168168404Spjd } 1169168404Spjd error = spa_set_props(spa, nvl); 1170168404Spjd } 1171168404Spjd 1172168404Spjd nvlist_free(nvl); 1173168404Spjd spa_close(spa, FTAG); 1174168404Spjd 1175168404Spjd return (error); 1176168404Spjd} 1177168404Spjd 1178168404Spjdstatic int 1179168404Spjdzfs_ioc_pool_props_get(zfs_cmd_t *zc) 1180168404Spjd{ 1181168404Spjd spa_t *spa; 1182168404Spjd int error; 1183168404Spjd nvlist_t *nvp = NULL; 1184168404Spjd 1185168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1186168404Spjd return (error); 1187168404Spjd 1188168404Spjd error = spa_get_props(spa, &nvp); 1189168404Spjd 1190168404Spjd if (error == 0 && zc->zc_nvlist_dst != 0) 1191168404Spjd error = put_nvlist(zc, nvp); 1192168404Spjd else 1193168404Spjd error = EFAULT; 1194168404Spjd 1195168404Spjd spa_close(spa, FTAG); 1196168404Spjd 1197168404Spjd if (nvp) 1198168404Spjd nvlist_free(nvp); 1199168404Spjd return (error); 1200168404Spjd} 1201168404Spjd 1202168404Spjdstatic int 1203168404Spjdzfs_ioc_create_minor(zfs_cmd_t *zc) 1204168404Spjd{ 1205168404Spjd return (zvol_create_minor(zc->zc_name, zc->zc_dev)); 1206168404Spjd} 1207168404Spjd 1208168404Spjdstatic int 1209168404Spjdzfs_ioc_remove_minor(zfs_cmd_t *zc) 1210168404Spjd{ 1211168404Spjd return (zvol_remove_minor(zc->zc_name)); 1212168404Spjd} 1213168404Spjd 1214168404Spjd/* 1215168404Spjd * Search the vfs list for a specified resource. Returns a pointer to it 1216168404Spjd * or NULL if no suitable entry is found. The caller of this routine 1217168404Spjd * is responsible for releasing the returned vfs pointer. 1218168404Spjd */ 1219168404Spjdstatic vfs_t * 1220168404Spjdzfs_get_vfs(const char *resource) 1221168404Spjd{ 1222168404Spjd vfs_t *vfsp; 1223168404Spjd 1224168404Spjd mtx_lock(&mountlist_mtx); 1225168404Spjd TAILQ_FOREACH(vfsp, &mountlist, mnt_list) { 1226168404Spjd if (strcmp(vfsp->mnt_stat.f_mntfromname, resource) == 0) { 1227168404Spjd VFS_HOLD(vfsp); 1228168404Spjd break; 1229168404Spjd } 1230168404Spjd } 1231168404Spjd mtx_unlock(&mountlist_mtx); 1232168404Spjd return (vfsp); 1233168404Spjd} 1234168404Spjd 1235168404Spjdstatic void 1236168404Spjdzfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx) 1237168404Spjd{ 1238168404Spjd zfs_create_data_t *zc = arg; 1239168404Spjd 1240168404Spjd zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx); 1241168404Spjd} 1242168404Spjd 1243168404Spjdstatic int 1244168404Spjdzfs_ioc_create(zfs_cmd_t *zc) 1245168404Spjd{ 1246168404Spjd objset_t *clone; 1247168404Spjd int error = 0; 1248168404Spjd zfs_create_data_t cbdata = { 0 }; 1249168404Spjd void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx); 1250168404Spjd dmu_objset_type_t type = zc->zc_objset_type; 1251168404Spjd 1252168404Spjd switch (type) { 1253168404Spjd 1254168404Spjd case DMU_OST_ZFS: 1255168404Spjd cbfunc = zfs_create_cb; 1256168404Spjd break; 1257168404Spjd 1258168404Spjd case DMU_OST_ZVOL: 1259168404Spjd cbfunc = zvol_create_cb; 1260168404Spjd break; 1261168404Spjd 1262168404Spjd default: 1263168404Spjd cbfunc = NULL; 1264168404Spjd } 1265168404Spjd if (strchr(zc->zc_name, '@')) 1266168404Spjd return (EINVAL); 1267168404Spjd 1268168404Spjd if (zc->zc_nvlist_src != 0 && 1269168404Spjd (error = get_nvlist(zc, &cbdata.zc_props)) != 0) 1270168404Spjd return (error); 1271168404Spjd 1272168404Spjd cbdata.zc_cred = (cred_t *)(uintptr_t)zc->zc_cred; 1273168404Spjd cbdata.zc_dev = (dev_t)zc->zc_dev; 1274168404Spjd 1275168404Spjd if (zc->zc_value[0] != '\0') { 1276168404Spjd /* 1277168404Spjd * We're creating a clone of an existing snapshot. 1278168404Spjd */ 1279168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1280168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { 1281168404Spjd nvlist_free(cbdata.zc_props); 1282168404Spjd return (EINVAL); 1283168404Spjd } 1284168404Spjd 1285168404Spjd error = dmu_objset_open(zc->zc_value, type, 1286168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &clone); 1287168404Spjd if (error) { 1288168404Spjd nvlist_free(cbdata.zc_props); 1289168404Spjd return (error); 1290168404Spjd } 1291168404Spjd error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); 1292168404Spjd dmu_objset_close(clone); 1293168404Spjd } else { 1294168404Spjd if (cbfunc == NULL) { 1295168404Spjd nvlist_free(cbdata.zc_props); 1296168404Spjd return (EINVAL); 1297168404Spjd } 1298168404Spjd 1299168404Spjd if (type == DMU_OST_ZVOL) { 1300168404Spjd uint64_t volsize, volblocksize; 1301168404Spjd 1302168404Spjd if (cbdata.zc_props == NULL || 1303168404Spjd nvlist_lookup_uint64(cbdata.zc_props, 1304168404Spjd zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1305168404Spjd &volsize) != 0) { 1306168404Spjd nvlist_free(cbdata.zc_props); 1307168404Spjd return (EINVAL); 1308168404Spjd } 1309168404Spjd 1310168404Spjd if ((error = nvlist_lookup_uint64(cbdata.zc_props, 1311168404Spjd zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 1312168404Spjd &volblocksize)) != 0 && error != ENOENT) { 1313168404Spjd nvlist_free(cbdata.zc_props); 1314168404Spjd return (EINVAL); 1315168404Spjd } 1316168404Spjd 1317168404Spjd if (error != 0) 1318168404Spjd volblocksize = zfs_prop_default_numeric( 1319168404Spjd ZFS_PROP_VOLBLOCKSIZE); 1320168404Spjd 1321168404Spjd if ((error = zvol_check_volblocksize( 1322168404Spjd volblocksize)) != 0 || 1323168404Spjd (error = zvol_check_volsize(volsize, 1324168404Spjd volblocksize)) != 0) { 1325168404Spjd nvlist_free(cbdata.zc_props); 1326168404Spjd return (error); 1327168404Spjd } 1328168404Spjd } 1329168404Spjd 1330168404Spjd error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, 1331168404Spjd &cbdata); 1332168404Spjd } 1333168404Spjd 1334168404Spjd /* 1335168404Spjd * It would be nice to do this atomically. 1336168404Spjd */ 1337168404Spjd if (error == 0) { 1338168404Spjd if ((error = zfs_set_prop_nvlist(zc->zc_name, 1339168404Spjd zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred, 1340168404Spjd cbdata.zc_props)) != 0) 1341168404Spjd (void) dmu_objset_destroy(zc->zc_name); 1342168404Spjd } 1343168404Spjd 1344168404Spjd nvlist_free(cbdata.zc_props); 1345168404Spjd return (error); 1346168404Spjd} 1347168404Spjd 1348168404Spjdstatic int 1349168404Spjdzfs_ioc_snapshot(zfs_cmd_t *zc) 1350168404Spjd{ 1351168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 1352168404Spjd return (EINVAL); 1353168404Spjd return (dmu_objset_snapshot(zc->zc_name, 1354168404Spjd zc->zc_value, zc->zc_cookie)); 1355168404Spjd} 1356168404Spjd 1357168676Spjdint 1358168404Spjdzfs_unmount_snap(char *name, void *arg) 1359168404Spjd{ 1360168404Spjd char *snapname = arg; 1361168404Spjd char *cp; 1362168404Spjd vfs_t *vfsp = NULL; 1363168404Spjd 1364168404Spjd /* 1365168404Spjd * Snapshots (which are under .zfs control) must be unmounted 1366168404Spjd * before they can be destroyed. 1367168404Spjd */ 1368168404Spjd 1369168404Spjd if (snapname) { 1370168404Spjd (void) strcat(name, "@"); 1371168404Spjd (void) strcat(name, snapname); 1372168404Spjd vfsp = zfs_get_vfs(name); 1373168404Spjd cp = strchr(name, '@'); 1374168404Spjd *cp = '\0'; 1375168404Spjd } else if (strchr(name, '@')) { 1376168404Spjd vfsp = zfs_get_vfs(name); 1377168404Spjd } 1378168404Spjd 1379168404Spjd if (vfsp) { 1380168404Spjd /* 1381168404Spjd * Always force the unmount for snapshots. 1382168404Spjd */ 1383168404Spjd int flag = MS_FORCE; 1384168404Spjd int err; 1385168404Spjd 1386168404Spjd if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { 1387168404Spjd VFS_RELE(vfsp); 1388168404Spjd return (err); 1389168404Spjd } 1390168404Spjd VFS_RELE(vfsp); 1391168404Spjd mtx_lock(&Giant); /* dounmount() */ 1392168404Spjd dounmount(vfsp, flag, curthread); 1393168404Spjd mtx_unlock(&Giant); /* dounmount() */ 1394168404Spjd } 1395168404Spjd return (0); 1396168404Spjd} 1397168404Spjd 1398168404Spjdstatic int 1399168404Spjdzfs_ioc_destroy_snaps(zfs_cmd_t *zc) 1400168404Spjd{ 1401168404Spjd int err; 1402168404Spjd 1403168404Spjd if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) 1404168404Spjd return (EINVAL); 1405168404Spjd err = dmu_objset_find(zc->zc_name, 1406168404Spjd zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); 1407168404Spjd if (err) 1408168404Spjd return (err); 1409168404Spjd return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); 1410168404Spjd} 1411168404Spjd 1412168404Spjdstatic int 1413168404Spjdzfs_ioc_destroy(zfs_cmd_t *zc) 1414168404Spjd{ 1415168404Spjd if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { 1416168404Spjd int err = zfs_unmount_snap(zc->zc_name, NULL); 1417168404Spjd if (err) 1418168404Spjd return (err); 1419168404Spjd } 1420168404Spjd 1421168404Spjd return (dmu_objset_destroy(zc->zc_name)); 1422168404Spjd} 1423168404Spjd 1424168404Spjdstatic int 1425168404Spjdzfs_ioc_rollback(zfs_cmd_t *zc) 1426168404Spjd{ 1427168404Spjd return (dmu_objset_rollback(zc->zc_name)); 1428168404Spjd} 1429168404Spjd 1430168404Spjdstatic int 1431168404Spjdzfs_ioc_rename(zfs_cmd_t *zc) 1432168404Spjd{ 1433168676Spjd int recursive = zc->zc_cookie & 1; 1434168676Spjd 1435168404Spjd zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; 1436168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) 1437168404Spjd return (EINVAL); 1438168404Spjd 1439168676Spjd /* 1440168676Spjd * Unmount snapshot unless we're doing a recursive rename, 1441168676Spjd * in which case the dataset code figures out which snapshots 1442168676Spjd * to unmount. 1443168676Spjd */ 1444168676Spjd if (!recursive && strchr(zc->zc_name, '@') != NULL && 1445168404Spjd zc->zc_objset_type == DMU_OST_ZFS) { 1446168404Spjd int err = zfs_unmount_snap(zc->zc_name, NULL); 1447168404Spjd if (err) 1448168404Spjd return (err); 1449168404Spjd } 1450168404Spjd 1451168676Spjd return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); 1452168404Spjd} 1453168404Spjd 1454168404Spjdstatic int 1455168404Spjdzfs_ioc_recvbackup(zfs_cmd_t *zc) 1456168404Spjd{ 1457168404Spjd kthread_t *td = curthread; 1458168404Spjd struct file *fp; 1459168404Spjd int error; 1460168404Spjd offset_t new_off; 1461168404Spjd 1462168404Spjd if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || 1463168404Spjd strchr(zc->zc_value, '@') == NULL) 1464168404Spjd return (EINVAL); 1465168404Spjd 1466168404Spjd error = fget_read(td, zc->zc_cookie, &fp); 1467168404Spjd if (error) 1468168404Spjd return (error); 1469168404Spjd 1470168404Spjd error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record, 1471168404Spjd &zc->zc_cookie, (boolean_t)zc->zc_guid, fp, 1472168404Spjd fp->f_offset); 1473168404Spjd 1474168404Spjd new_off = fp->f_offset + zc->zc_cookie; 1475168404Spjd fp->f_offset = new_off; 1476168404Spjd 1477168404Spjd fdrop(fp, td); 1478168404Spjd return (error); 1479168404Spjd} 1480168404Spjd 1481168404Spjdstatic int 1482168404Spjdzfs_ioc_sendbackup(zfs_cmd_t *zc) 1483168404Spjd{ 1484168404Spjd kthread_t *td = curthread; 1485168404Spjd struct file *fp; 1486168404Spjd objset_t *fromsnap = NULL; 1487168404Spjd objset_t *tosnap; 1488168404Spjd int error, fd; 1489168404Spjd 1490168404Spjd error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, 1491168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); 1492168404Spjd if (error) 1493168404Spjd return (error); 1494168404Spjd 1495168404Spjd if (zc->zc_value[0] != '\0') { 1496168404Spjd char buf[MAXPATHLEN]; 1497168404Spjd char *cp; 1498168404Spjd 1499168404Spjd (void) strncpy(buf, zc->zc_name, sizeof (buf)); 1500168404Spjd cp = strchr(buf, '@'); 1501168404Spjd if (cp) 1502168404Spjd *(cp+1) = 0; 1503168404Spjd (void) strlcat(buf, zc->zc_value, sizeof (buf)); 1504168404Spjd error = dmu_objset_open(buf, DMU_OST_ANY, 1505168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); 1506168404Spjd if (error) { 1507168404Spjd dmu_objset_close(tosnap); 1508168404Spjd return (error); 1509168404Spjd } 1510168404Spjd } 1511168404Spjd 1512168404Spjd fd = zc->zc_cookie; 1513168404Spjd error = fget_write(td, fd, &fp); 1514168404Spjd if (error) { 1515168404Spjd dmu_objset_close(tosnap); 1516168404Spjd if (fromsnap) 1517168404Spjd dmu_objset_close(fromsnap); 1518168404Spjd return (error); 1519168404Spjd } 1520168404Spjd 1521168404Spjd error = dmu_sendbackup(tosnap, fromsnap, fp); 1522168404Spjd 1523168404Spjd fdrop(fp, td); 1524168404Spjd if (fromsnap) 1525168404Spjd dmu_objset_close(fromsnap); 1526168404Spjd dmu_objset_close(tosnap); 1527168404Spjd return (error); 1528168404Spjd} 1529168404Spjd 1530168404Spjdstatic int 1531168404Spjdzfs_ioc_inject_fault(zfs_cmd_t *zc) 1532168404Spjd{ 1533168404Spjd int id, error; 1534168404Spjd 1535168404Spjd error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, 1536168404Spjd &zc->zc_inject_record); 1537168404Spjd 1538168404Spjd if (error == 0) 1539168404Spjd zc->zc_guid = (uint64_t)id; 1540168404Spjd 1541168404Spjd return (error); 1542168404Spjd} 1543168404Spjd 1544168404Spjdstatic int 1545168404Spjdzfs_ioc_clear_fault(zfs_cmd_t *zc) 1546168404Spjd{ 1547168404Spjd return (zio_clear_fault((int)zc->zc_guid)); 1548168404Spjd} 1549168404Spjd 1550168404Spjdstatic int 1551168404Spjdzfs_ioc_inject_list_next(zfs_cmd_t *zc) 1552168404Spjd{ 1553168404Spjd int id = (int)zc->zc_guid; 1554168404Spjd int error; 1555168404Spjd 1556168404Spjd error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), 1557168404Spjd &zc->zc_inject_record); 1558168404Spjd 1559168404Spjd zc->zc_guid = id; 1560168404Spjd 1561168404Spjd return (error); 1562168404Spjd} 1563168404Spjd 1564168404Spjdstatic int 1565168404Spjdzfs_ioc_error_log(zfs_cmd_t *zc) 1566168404Spjd{ 1567168404Spjd spa_t *spa; 1568168404Spjd int error; 1569168404Spjd size_t count = (size_t)zc->zc_nvlist_dst_size; 1570168404Spjd 1571168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1572168404Spjd return (error); 1573168404Spjd 1574168404Spjd error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, 1575168404Spjd &count); 1576168404Spjd if (error == 0) 1577168404Spjd zc->zc_nvlist_dst_size = count; 1578168404Spjd else 1579168404Spjd zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); 1580168404Spjd 1581168404Spjd spa_close(spa, FTAG); 1582168404Spjd 1583168404Spjd return (error); 1584168404Spjd} 1585168404Spjd 1586168404Spjdstatic int 1587168404Spjdzfs_ioc_clear(zfs_cmd_t *zc) 1588168404Spjd{ 1589168404Spjd spa_t *spa; 1590168404Spjd vdev_t *vd; 1591168404Spjd int error; 1592168404Spjd 1593168404Spjd if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) 1594168404Spjd return (error); 1595168404Spjd 1596168404Spjd spa_config_enter(spa, RW_WRITER, FTAG); 1597168404Spjd 1598168404Spjd if (zc->zc_guid == 0) { 1599168404Spjd vd = NULL; 1600168404Spjd } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { 1601168404Spjd spa_config_exit(spa, FTAG); 1602168404Spjd spa_close(spa, FTAG); 1603168404Spjd return (ENODEV); 1604168404Spjd } 1605168404Spjd 1606168404Spjd vdev_clear(spa, vd); 1607168404Spjd 1608168404Spjd spa_config_exit(spa, FTAG); 1609168404Spjd 1610168404Spjd spa_close(spa, FTAG); 1611168404Spjd 1612168404Spjd return (0); 1613168404Spjd} 1614168404Spjd 1615168404Spjdstatic int 1616168404Spjdzfs_ioc_promote(zfs_cmd_t *zc) 1617168404Spjd{ 1618168404Spjd char *cp; 1619168404Spjd 1620168404Spjd /* 1621168404Spjd * We don't need to unmount *all* the origin fs's snapshots, but 1622168404Spjd * it's easier. 1623168404Spjd */ 1624168404Spjd cp = strchr(zc->zc_value, '@'); 1625168404Spjd if (cp) 1626168404Spjd *cp = '\0'; 1627168404Spjd (void) dmu_objset_find(zc->zc_value, 1628168404Spjd zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); 1629168404Spjd return (dsl_dataset_promote(zc->zc_name)); 1630168404Spjd} 1631168404Spjd 1632168404Spjdstatic int 1633168404Spjdzfs_ioc_jail(zfs_cmd_t *zc) 1634168404Spjd{ 1635168404Spjd 1636168404Spjd return (zone_dataset_attach((cred_t *)(uintptr_t)zc->zc_cred, 1637168404Spjd zc->zc_name, (int)zc->zc_jailid)); 1638168404Spjd} 1639168404Spjd 1640168404Spjdstatic int 1641168404Spjdzfs_ioc_unjail(zfs_cmd_t *zc) 1642168404Spjd{ 1643168404Spjd 1644168404Spjd return (zone_dataset_detach((cred_t *)(uintptr_t)zc->zc_cred, 1645168404Spjd zc->zc_name, (int)zc->zc_jailid)); 1646168404Spjd} 1647168404Spjd 1648168404Spjdstatic zfs_ioc_vec_t zfs_ioc_vec[] = { 1649168404Spjd { zfs_ioc_pool_create, zfs_secpolicy_config, pool_name }, 1650168404Spjd { zfs_ioc_pool_destroy, zfs_secpolicy_config, pool_name }, 1651168404Spjd { zfs_ioc_pool_import, zfs_secpolicy_config, pool_name }, 1652168404Spjd { zfs_ioc_pool_export, zfs_secpolicy_config, pool_name }, 1653168404Spjd { zfs_ioc_pool_configs, zfs_secpolicy_none, no_name }, 1654168404Spjd { zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name }, 1655168404Spjd { zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name }, 1656168404Spjd { zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name }, 1657168404Spjd { zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name }, 1658168404Spjd { zfs_ioc_pool_upgrade, zfs_secpolicy_config, pool_name }, 1659168404Spjd { zfs_ioc_pool_get_history, zfs_secpolicy_config, pool_name }, 1660168404Spjd { zfs_ioc_pool_log_history, zfs_secpolicy_config, pool_name }, 1661168404Spjd { zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name }, 1662168404Spjd { zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name }, 1663168404Spjd { zfs_ioc_vdev_online, zfs_secpolicy_config, pool_name }, 1664168404Spjd { zfs_ioc_vdev_offline, zfs_secpolicy_config, pool_name }, 1665168404Spjd { zfs_ioc_vdev_attach, zfs_secpolicy_config, pool_name }, 1666168404Spjd { zfs_ioc_vdev_detach, zfs_secpolicy_config, pool_name }, 1667168404Spjd { zfs_ioc_vdev_setpath, zfs_secpolicy_config, pool_name }, 1668168404Spjd { zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name }, 1669168404Spjd { zfs_ioc_dataset_list_next, zfs_secpolicy_read, dataset_name }, 1670168404Spjd { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, dataset_name }, 1671168404Spjd { zfs_ioc_set_prop, zfs_secpolicy_write, dataset_name }, 1672168404Spjd { zfs_ioc_create_minor, zfs_secpolicy_config, dataset_name }, 1673168404Spjd { zfs_ioc_remove_minor, zfs_secpolicy_config, dataset_name }, 1674168404Spjd { zfs_ioc_create, zfs_secpolicy_parent, dataset_name }, 1675168404Spjd { zfs_ioc_destroy, zfs_secpolicy_parent, dataset_name }, 1676168404Spjd { zfs_ioc_rollback, zfs_secpolicy_write, dataset_name }, 1677168404Spjd { zfs_ioc_rename, zfs_secpolicy_write, dataset_name }, 1678168404Spjd { zfs_ioc_recvbackup, zfs_secpolicy_write, dataset_name }, 1679168404Spjd { zfs_ioc_sendbackup, zfs_secpolicy_operator, dataset_name }, 1680168404Spjd { zfs_ioc_inject_fault, zfs_secpolicy_inject, no_name }, 1681168404Spjd { zfs_ioc_clear_fault, zfs_secpolicy_inject, no_name }, 1682168404Spjd { zfs_ioc_inject_list_next, zfs_secpolicy_inject, no_name }, 1683168404Spjd { zfs_ioc_error_log, zfs_secpolicy_inject, pool_name }, 1684168404Spjd { zfs_ioc_clear, zfs_secpolicy_config, pool_name }, 1685168404Spjd { zfs_ioc_promote, zfs_secpolicy_write, dataset_name }, 1686168404Spjd { zfs_ioc_destroy_snaps, zfs_secpolicy_write, dataset_name }, 1687168404Spjd { zfs_ioc_snapshot, zfs_secpolicy_operator, dataset_name }, 1688168404Spjd { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, pool_name }, 1689168404Spjd { zfs_ioc_obj_to_path, zfs_secpolicy_config, no_name }, 1690168404Spjd { zfs_ioc_pool_props_set, zfs_secpolicy_config, pool_name }, 1691168404Spjd { zfs_ioc_pool_props_get, zfs_secpolicy_read, pool_name }, 1692168404Spjd { zfs_ioc_jail, zfs_secpolicy_config, dataset_name }, 1693168404Spjd { zfs_ioc_unjail, zfs_secpolicy_config, dataset_name } 1694168404Spjd}; 1695168404Spjd 1696168404Spjdstatic int 1697168404Spjdzfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 1698168404Spjd struct thread *td) 1699168404Spjd{ 1700168404Spjd zfs_cmd_t *zc = (void *)addr; 1701168404Spjd uint_t vec; 1702168404Spjd int error; 1703168404Spjd 1704168404Spjd vec = ZFS_IOC(cmd); 1705168404Spjd 1706168404Spjd if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) 1707168404Spjd return (EINVAL); 1708168404Spjd 1709168404Spjd zc->zc_cred = (uintptr_t)td->td_ucred; 1710168404Spjd zc->zc_dev = (uintptr_t)dev; 1711168404Spjd error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, td->td_ucred); 1712168404Spjd 1713168404Spjd /* 1714168404Spjd * Ensure that all pool/dataset names are valid before we pass down to 1715168404Spjd * the lower layers. 1716168404Spjd */ 1717168404Spjd if (error == 0) { 1718168404Spjd zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; 1719168404Spjd switch (zfs_ioc_vec[vec].zvec_namecheck) { 1720168404Spjd case pool_name: 1721168404Spjd if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) 1722168404Spjd error = EINVAL; 1723168404Spjd break; 1724168404Spjd 1725168404Spjd case dataset_name: 1726168404Spjd if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) 1727168404Spjd error = EINVAL; 1728168404Spjd break; 1729168404Spjd 1730168404Spjd case no_name: 1731168404Spjd break; 1732168404Spjd } 1733168404Spjd } 1734168404Spjd 1735168404Spjd if (error == 0) 1736168404Spjd error = zfs_ioc_vec[vec].zvec_func(zc); 1737168404Spjd 1738168404Spjd return (error); 1739168404Spjd} 1740168404Spjd 1741168404Spjd/* 1742168404Spjd * OK, so this is a little weird. 1743168404Spjd * 1744168404Spjd * /dev/zfs is the control node, i.e. minor 0. 1745168404Spjd * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. 1746168404Spjd * 1747168404Spjd * /dev/zfs has basically nothing to do except serve up ioctls, 1748168404Spjd * so most of the standard driver entry points are in zvol.c. 1749168404Spjd */ 1750168404Spjdstatic struct cdevsw zfs_cdevsw = { 1751168404Spjd .d_version = D_VERSION, 1752168404Spjd .d_ioctl = zfsdev_ioctl, 1753168404Spjd .d_name = ZFS_DEV_NAME 1754168404Spjd}; 1755168404Spjd 1756168404Spjdstatic void 1757168404Spjdzfsdev_init(void) 1758168404Spjd{ 1759168404Spjd zfsdev = make_dev(&zfs_cdevsw, 0x0, UID_ROOT, GID_OPERATOR, 0660, 1760168404Spjd ZFS_DEV_NAME); 1761168404Spjd} 1762168404Spjd 1763168404Spjdstatic void 1764168404Spjdzfsdev_fini(void) 1765168404Spjd{ 1766168404Spjd if (zfsdev != NULL) 1767168404Spjd destroy_dev(zfsdev); 1768168404Spjd} 1769168404Spjd 1770168404Spjdstatic struct task zfs_start_task; 1771168404Spjd 1772168404Spjdstatic void 1773168404Spjdzfs_start(void *context __unused, int pending __unused) 1774168404Spjd{ 1775168404Spjd 1776168404Spjd zfsdev_init(); 1777168404Spjd spa_init(FREAD | FWRITE); 1778168404Spjd zfs_init(); 1779168404Spjd zvol_init(); 1780168404Spjd printf("ZFS storage pool version " ZFS_VERSION_STRING "\n"); 1781168404Spjd} 1782168404Spjd 1783168404Spjdstatic int 1784168404Spjdzfs_modevent(module_t mod, int type, void *unused __unused) 1785168404Spjd{ 1786168404Spjd int error; 1787168404Spjd 1788168404Spjd error = EOPNOTSUPP; 1789168404Spjd switch (type) { 1790168404Spjd case MOD_LOAD: 1791168404Spjd printf("WARNING: ZFS is considered to be an experimental " 1792168404Spjd "feature in FreeBSD.\n"); 1793168404Spjd TASK_INIT(&zfs_start_task, 0, zfs_start, NULL); 1794168404Spjd taskqueue_enqueue(taskqueue_thread, &zfs_start_task); 1795168404Spjd error = 0; 1796168404Spjd break; 1797168404Spjd case MOD_UNLOAD: 1798168775Spjd if (spa_busy() || zfs_busy() || zvol_busy() || 1799168404Spjd zio_injection_enabled) { 1800168404Spjd error = EBUSY; 1801168404Spjd break; 1802168404Spjd } 1803168404Spjd zvol_fini(); 1804168404Spjd zfs_fini(); 1805168404Spjd spa_fini(); 1806168404Spjd zfsdev_fini(); 1807168404Spjd error = 0; 1808168404Spjd break; 1809168404Spjd } 1810168404Spjd return (error); 1811168404Spjd} 1812168404Spjd 1813168404Spjdstatic moduledata_t zfs_mod = { 1814168404Spjd "zfsctrl", 1815168404Spjd zfs_modevent, 1816168404Spjd 0 1817168404Spjd}; 1818168404SpjdDECLARE_MODULE(zfsctrl, zfs_mod, SI_SUB_MOUNT_ROOT, SI_ORDER_ANY); 1819