Print this page
8520 lzc_rollback_to should support rolling back to origin
7198 libzfs should gracefully handle EINVAL from lzc_rollback
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Dan McDonald <danmcd@joyent.com>
NEX-16623 Ability to set properties for multiple datasets/snapshots during single sync-round
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-16502 libshare needs to support SMB in a zone
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-8600 Destroying a KRRP session takes too long
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5736 implement autoreplace matching based on FRU slot number
NEX-6200 hot spares are not reactivated after reinserting into enclosure
NEX-9403 need to update FRU for spare and l2cache devices
NEX-9404 remove lofi autoreplace support from syseventd
NEX-9409 hotsparing doesn't work for vdevs without FRU
NEX-9424 zfs`vdev_online() needs better notification about state changes
Portions contributed by: Alek Pinchuk <alek@nexenta.com>
Portions contributed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-8827 AUTOSNAP: can't register recursive zone when there is a child under autosnappool/volumegrou
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-8106 async ZFS event notifications don't need to announce publish failure
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-6490 Unable to destroy filesystem with receive_resume_token
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-6213 KRRP: System panics if recv-stream does not have snap-properties
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-5553 ZFS auto-trim, manual-trim and scrub can race and deadlock
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5795 Rename 'wrc' as 'wbc' in the source and in the tech docs
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5272 KRRP: replicate snapshot properties
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5268 WBC: add sysevent migration-done
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5060 WBC: Writecache and deduplication should not be used together
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4830 writecache=off leaks data on special vdev (the data will never migrate)
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4608 WRC: Possible deadlock during the disabling of WRC for a dataset
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
4986 receiving replication stream fails if any snapshot exceeds refquota
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Gordon Ross <gordon.ross@nexenta.com>
6388 Failure of userland copy should return EFAULT
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Dan Kimmel <dan.kimmel@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
6328 Fix cstyle errors in zfs codebase (fix studio)
6328 Fix cstyle errors in zfs codebase
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Jorgen Lundman <lundman@lundman.net>
Approved by: Robert Mustacchi <rm@joyent.com>
2605 want to resume interrupted zfs send
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Xin Li <delphij@freebsd.org>
Reviewed by: Arne Jansen <sensille@gmx.net>
Approved by: Dan McDonald <danmcd@omniti.com>
6286 ZFS internal error when set large block on bootfs
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Andriy Gapon <avg@FreeBSD.org>
Approved by: Robert Mustacchi <rm@joyent.com>
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R (fix studio build)
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Garrett D'Amore <garrett@damore.org>
6096 ZFS_SMB_ACL_RENAME needs to cleanup better
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: George Wilson <gwilson@zfsmail.com>
Approved by: Robert Mustacchi <rm@joyent.com>
5946 zfs_ioc_space_snaps must check that firstsnap and lastsnap refer to snapshots
5945 zfs_ioc_send_space must ensure that fromsnap refers to a snapshot
Reviewed by: Steven Hartland <killing@multiplay.co.uk>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Gordon Ross <gordon.ross@nexenta.com>
5515 dataset user hold doesn't reject empty tags
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Approved by: Matthew Ahrens <mahrens@delphix.com>
5765 add support for estimating send stream size with lzc_send_space when source is a bookmark
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Steven Hartland <killing@multiplay.co.uk>
Reviewed by: Bayard Bell <buffer.g.overflow@gmail.com>
Approved by: Albert Lee <trisk@nexenta.com>
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Revert "NEX-4476 WRC: Allow to use write back cache per tree of datasets"
This reverts commit fe97b74444278a6f36fec93179133641296312da.
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-4194 WRC does not migrate data when idle
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-4206 Event 'recv' should contain information that received ds is new
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
NEX-4044 remove sha1crc32 in preparation with upstream merge of edon-r and skien
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Conflicts:
        usr/src/uts/common/fs/zfs/sys/zio_checksum.h
NEX-3984 On-demand TRIM
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Conflicts:
        usr/src/common/zfs/zpool_prop.c
        usr/src/uts/common/sys/fs/zfs.h
NEX-3964 It should not be allowed to rename a snapshot that its new name is matched to the prefix of in-kernel autosnapshots
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3878 Bogus address kernel panic in nvlist_copy_pairs from snmpd whilst exporting a zpool
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3921 Memory leaks in ZFS_IOC_OBJSET_STATS_NVL implementation
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-3010 e1000g use after free on start failure
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3731 fixed incorrect behavior of zpool export/destroy for faulted pool that is caused by krrp-check (lint)
NEX-3731 fixed incorrect behavior of zpool export/destroy for faulted pool that is caused by krrp-check
 Reviewed by: Alek Pinchuk <alek@nexenta.com>
 Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-3723 Want ZFS dataset bulk listing support
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
NEX-2195 zfs panic assertion failed: strcmp(zn->zn_key_orig, mze->mze_name) != 0
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-3726 CBC decrypt returns encrypted data
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3709 Fixed KRRP/WRC code style and KRRP related warnings that are showed by 'git nits'
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3558 KRRP Integration
NEX-3165 need some dedup improvements
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-3070 Panic in zpool_create_features_002_pos test
NEX-2935 want async notification for certain ZFS changes (fix)
NEX-2935 want async notification for certain ZFS changes (lint)
NEX-2935 want async notification for certain ZFS changes
OS-103 handle CoS descriptor persistent references across vdev operations
OS-102 add man page info and tests for vdev/CoS properties and ZFS meta features
OS-80 support for vdev and CoS properties for the new I/O scheduler
OS-95 lint warning introduced by OS-61
Remaining fixes for the illumos merge
Moved closed ZFS files to open repo, changed Makefiles accordingly
Removed unneeded weak symbols
Issue #34: Add feature flag for the compount checksum - sha1crc32
           Contributors: Boris Protopopov
Fixup merge results
OS-15 ensure that truss continues to work
OS-15 revert changes to put_nvlist
re #13850 Refactor ZFS config discovery IOCs to libzfs_core patterns
re 13748 added zpool export -c option
zpool export -c command exports specified pool while keeping its latest
configuration in the cache file for subsequent zpool import -c.
re #12619 rb4429 More dp->dp_config_rwlock holds
re #13204 rb4280 zfs receive/rollback deadlock
re #12585 rb4049 ZFS++ work port - refactoring to improve separation of open/closed code, bug fixes, performance improvements - open code
Bug 11205: add missing libzfs_closed_stubs.c to fix opensource-only build.
ZFS plus work: special vdevs, cos, cos/vdev properties
Bug 10481 - Dry run option in 'zfs send' isn't the same as in NexentaStor 3.1
re #7550 rb2134 lint-clean nza-kernel
re #6815 rb1758 need WORM in nza-kernel (4.0)

*** 19,37 **** * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved. * Portions Copyright 2011 Martin Matuska * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved. * Copyright (c) 2011, 2017 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Toomas Soome <tsoome@me.com> * Copyright 2017 RackTop Systems. * Copyright (c) 2017 Datto Inc. */ --- 19,40 ---- * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + */ + + /* * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved. * Portions Copyright 2011 Martin Matuska * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved. * Copyright (c) 2011, 2017 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2014 Integros [integros.com] + * Copyright 2018 Nexenta Systems, Inc. * Copyright 2016 Toomas Soome <tsoome@me.com> * Copyright 2017 RackTop Systems. * Copyright (c) 2017 Datto Inc. */
*** 154,168 **** --- 157,173 ---- #include <sys/zap.h> #include <sys/spa.h> #include <sys/spa_impl.h> #include <sys/vdev.h> #include <sys/priv_impl.h> + #include <sys/autosnap.h> #include <sys/dmu.h> #include <sys/dsl_dir.h> #include <sys/dsl_dataset.h> #include <sys/dsl_prop.h> #include <sys/dsl_deleg.h> + #include <sys/dsl_synctask.h> #include <sys/dmu_objset.h> #include <sys/dmu_impl.h> #include <sys/dmu_tx.h> #include <sys/ddi.h> #include <sys/sunddi.h>
*** 184,201 **** #include <sys/dmu_send.h> #include <sys/dsl_destroy.h> #include <sys/dsl_bookmark.h> #include <sys/dsl_userhold.h> #include <sys/zfeature.h> #include <sys/zcp.h> #include <sys/zio_checksum.h> - #include <sys/vdev_removal.h> #include "zfs_namecheck.h" #include "zfs_prop.h" #include "zfs_deleg.h" #include "zfs_comutil.h" #include "lua.h" #include "lauxlib.h" extern struct modlfs zfs_modlfs; --- 189,211 ---- #include <sys/dmu_send.h> #include <sys/dsl_destroy.h> #include <sys/dsl_bookmark.h> #include <sys/dsl_userhold.h> #include <sys/zfeature.h> + #include <sys/cos.h> + #include <sys/cos_impl.h> + #include <sys/zfeature.h> + #include <sys/sysevent.h> + #include <sys/sysevent_impl.h> #include <sys/zcp.h> #include <sys/zio_checksum.h> #include "zfs_namecheck.h" #include "zfs_prop.h" #include "zfs_deleg.h" #include "zfs_comutil.h" + #include "zfs_errno.h" #include "lua.h" #include "lauxlib.h" extern struct modlfs zfs_modlfs;
*** 255,264 **** --- 265,307 ---- int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *); static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp); static int zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature); + static int + zfs_is_wormed_ds(dsl_dataset_t *ds) + { + char worminfo[13] = {0}; + + if (dsl_prop_get_ds(ds, "nms:worm", 1, 12, &worminfo, NULL) == 0 && + worminfo[0] && strcmp(worminfo, "0") != 0 && + strcmp(worminfo, "off") != 0 && strcmp(worminfo, "-") != 0) { + return (1); + } + return (0); + } + + static int + zfs_is_wormed(const char *name) + { + char worminfo[13] = {0}; + char cname[MAXNAMELEN]; + char *end; + + (void) strlcpy(cname, name, MAXNAMELEN); + end = strchr(cname, '@'); + if (end) + *end = 0; + + if (dsl_prop_get(cname, "nms:worm", 1, 12, &worminfo, NULL) == 0 && + worminfo[0] && strcmp(worminfo, "0") != 0 && + strcmp(worminfo, "off") != 0 && strcmp(worminfo, "-") != 0) { + return (1); + } + return (0); + } + /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ void __dprintf(const char *file, const char *func, int line, const char *fmt, ...) { const char *newfile;
*** 770,782 **** } int zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) { - if (!INGLOBALZONE(curproc)) - return (SET_ERROR(EPERM)); - if (secpolicy_nfs(cr) == 0) { return (0); } else { return (zfs_secpolicy_deleg_share(zc, innvl, cr)); } --- 813,822 ----
*** 783,795 **** } int zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) { - if (!INGLOBALZONE(curproc)) - return (SET_ERROR(EPERM)); - if (secpolicy_smb(cr) == 0) { return (0); } else { return (zfs_secpolicy_deleg_share(zc, innvl, cr)); } --- 823,832 ----
*** 1041,1058 **** return (error); } /* ARGSUSED */ static int - zfs_secpolicy_remap(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) - { - return (zfs_secpolicy_write_perms(zc->zc_name, - ZFS_DELEG_PERM_REMAP, cr)); - } - - /* ARGSUSED */ - static int zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) { nvpair_t *pair, *nextpair; int error = 0; --- 1078,1087 ----
*** 1381,1414 **** } return (0); } static int put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) { char *packed = NULL; int error = 0; size_t size; size = fnvlist_size(nvl); if (size > zc->zc_nvlist_dst_size) { error = SET_ERROR(ENOMEM); } else { packed = fnvlist_pack(nvl, &size); if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0) error = SET_ERROR(EFAULT); fnvlist_pack_free(packed, size); } zc->zc_nvlist_dst_size = size; - zc->zc_nvlist_dst_filled = B_TRUE; return (error); } int getzfsvfs_impl(objset_t *os, zfsvfs_t **zfvp) { int error = 0; if (dmu_objset_type(os) != DMU_OST_ZFS) { --- 1410,1488 ---- } return (0); } + /* + * Callers will know whether there's anything to unpack based on ret non-0/errno + * set to ENOMEM, but observers (e.g truss) need the message properly marked to + * know if it should be unpacked and displayed. Don't marked as filled unless + * completely successful. If there's a non-empty nvlist, set size to its nvl + * size as resize hint. + */ static int put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) { char *packed = NULL; int error = 0; size_t size; size = fnvlist_size(nvl); + zc->zc_nvlist_dst_filled = B_FALSE; if (size > zc->zc_nvlist_dst_size) { error = SET_ERROR(ENOMEM); } else { packed = fnvlist_pack(nvl, &size); if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0) error = SET_ERROR(EFAULT); + else + zc->zc_nvlist_dst_filled = B_TRUE; fnvlist_pack_free(packed, size); } zc->zc_nvlist_dst_size = size; return (error); } + static int + getzfsvfs_from_ds(dsl_dataset_t *ds, zfsvfs_t **zfvp) + { + objset_t *os; + int error; + dsl_pool_t *dp; + + dp = ds->ds_dir->dd_pool; + dsl_pool_config_enter(dp, FTAG); + + /* + * IU: we probably need to hold dataset here. + * For now let's assume we do. + * May need revision later. + */ + dsl_dataset_long_hold(ds, FTAG); + error = dmu_objset_from_ds(ds, &os); + if (dmu_objset_type(os) != DMU_OST_ZFS) { + dsl_dataset_long_rele(ds, FTAG); + dsl_pool_config_exit(dp, FTAG); + return (EINVAL); + } + + mutex_enter(&os->os_user_ptr_lock); + *zfvp = dmu_objset_get_user(os); + if (*zfvp) { + VFS_HOLD((*zfvp)->z_vfs); + } else { + error = ESRCH; + } + mutex_exit(&os->os_user_ptr_lock); + dsl_dataset_long_rele(ds, FTAG); + dsl_pool_config_exit(dp, FTAG); + return (error); + } + int getzfsvfs_impl(objset_t *os, zfsvfs_t **zfvp) { int error = 0; if (dmu_objset_type(os) != DMU_OST_ZFS) {
*** 1481,1497 **** --- 1555,1595 ---- dmu_objset_disown(zfsvfs->z_os, zfsvfs); zfsvfs_free(zfsvfs); } } + + /* + * Publish events using GPEC subsystem + */ + + static evchan_t *zfs_channel = NULL; + + void + zfs_event_post(const char *subclass, const char *operation, nvlist_t *ev_data) + { + + if (zfs_channel == NULL) + goto out; + + fnvlist_add_string(ev_data, "operation", operation); + + (void) sysevent_evc_publish(zfs_channel, subclass, operation, + "com.nexenta", "zfs-kernel", ev_data, EVCH_NOSLEEP); + + out: + fnvlist_free(ev_data); + } + static int zfs_ioc_pool_create(zfs_cmd_t *zc) { int error; nvlist_t *config, *props = NULL; nvlist_t *rootprops = NULL; nvlist_t *zplprops = NULL; + nvlist_t *event; if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, zc->zc_iflags, &config)) return (error);
*** 1536,1545 **** --- 1634,1652 ---- */ if (!error && (error = zfs_set_prop_nvlist(zc->zc_name, ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) (void) spa_destroy(zc->zc_name); + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "name", zc->zc_name); + fnvlist_add_nvlist(event, "config", config); + if (props != NULL) + fnvlist_add_nvlist(event, "props", props); + zfs_event_post(ZPOOL_EC_STATUS, "create", event); + } + pool_props_bad: nvlist_free(rootprops); nvlist_free(zplprops); nvlist_free(config); nvlist_free(props);
*** 1549,1571 **** static int zfs_ioc_pool_destroy(zfs_cmd_t *zc) { int error; zfs_log_history(zc); error = spa_destroy(zc->zc_name); ! if (error == 0) zvol_remove_minors(zc->zc_name); return (error); } static int zfs_ioc_pool_import(zfs_cmd_t *zc) { nvlist_t *config, *props = NULL; uint64_t guid; int error; if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, zc->zc_iflags, &config)) != 0) return (error); --- 1656,1684 ---- static int zfs_ioc_pool_destroy(zfs_cmd_t *zc) { int error; + nvlist_t *event; zfs_log_history(zc); error = spa_destroy(zc->zc_name); ! if (error == 0) { zvol_remove_minors(zc->zc_name); + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + zfs_event_post(ZPOOL_EC_STATUS, "destroy", event); + } return (error); } static int zfs_ioc_pool_import(zfs_cmd_t *zc) { nvlist_t *config, *props = NULL; uint64_t guid; int error; + nvlist_t *event; if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, zc->zc_iflags, &config)) != 0) return (error);
*** 1580,1589 **** --- 1693,1712 ---- guid != zc->zc_guid) error = SET_ERROR(EINVAL); else error = spa_import(zc->zc_name, config, props, zc->zc_cookie); + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + fnvlist_add_uint64(event, "guid", zc->zc_guid); + fnvlist_add_nvlist(event, "config", config); + if (props != NULL) + fnvlist_add_nvlist(event, "props", props); + zfs_event_post(ZPOOL_EC_STATUS, "import", event); + } + if (zc->zc_nvlist_dst != 0) { int err; if ((err = put_nvlist(zc, config)) != 0) error = err;
*** 1600,1614 **** zfs_ioc_pool_export(zfs_cmd_t *zc) { int error; boolean_t force = (boolean_t)zc->zc_cookie; boolean_t hardforce = (boolean_t)zc->zc_guid; zfs_log_history(zc); ! error = spa_export(zc->zc_name, NULL, force, hardforce); ! if (error == 0) zvol_remove_minors(zc->zc_name); return (error); } static int zfs_ioc_pool_configs(zfs_cmd_t *zc) --- 1723,1743 ---- zfs_ioc_pool_export(zfs_cmd_t *zc) { int error; boolean_t force = (boolean_t)zc->zc_cookie; boolean_t hardforce = (boolean_t)zc->zc_guid; + boolean_t saveconfig = (boolean_t)zc->zc_obj; + nvlist_t *event; zfs_log_history(zc); ! error = spa_export(zc->zc_name, NULL, force, hardforce, saveconfig); ! if (error == 0) { zvol_remove_minors(zc->zc_name); + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + zfs_event_post(ZPOOL_EC_STATUS, "export", event); + } return (error); } static int zfs_ioc_pool_configs(zfs_cmd_t *zc)
*** 1717,1727 **** --- 1846,1886 ---- spa_close(spa, FTAG); return (error); } + /* + * inputs: + * zc_name name of the pool + * zc_cookie trim_cmd_info_t + */ static int + zfs_ioc_pool_trim(zfs_cmd_t *zc) + { + spa_t *spa; + int error; + trim_cmd_info_t tci; + + if (ddi_copyin((void *)(uintptr_t)zc->zc_cookie, &tci, + sizeof (tci), 0) == -1) + return (EFAULT); + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) + return (error); + + if (tci.tci_start) { + spa_man_trim(spa, tci.tci_rate); + } else { + spa_man_trim_stop(spa); + } + + spa_close(spa, FTAG); + + return (error); + } + + static int zfs_ioc_pool_freeze(zfs_cmd_t *zc) { spa_t *spa; int error;
*** 1868,1877 **** --- 2027,2037 ---- { spa_t *spa; int error; nvlist_t *config, **l2cache, **spares; uint_t nl2cache = 0, nspares = 0; + nvlist_t *event; error = spa_open(zc->zc_name, &spa, FTAG); if (error != 0) return (error);
*** 1899,1934 **** return (SET_ERROR(EDOM)); } if (error == 0) { error = spa_vdev_add(spa, config); nvlist_free(config); } spa_close(spa, FTAG); return (error); } /* * inputs: * zc_name name of the pool ! * zc_guid guid of vdev to remove ! * zc_cookie cancel removal */ static int zfs_ioc_vdev_remove(zfs_cmd_t *zc) { spa_t *spa; int error; error = spa_open(zc->zc_name, &spa, FTAG); if (error != 0) return (error); - if (zc->zc_cookie != 0) { - error = spa_vdev_remove_cancel(spa); - } else { error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); } spa_close(spa, FTAG); return (error); } static int --- 2059,2105 ---- return (SET_ERROR(EDOM)); } if (error == 0) { error = spa_vdev_add(spa, config); + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + fnvlist_add_nvlist(event, "config", config); + zfs_event_post(ZPOOL_EC_STATUS, "add", event); + + } nvlist_free(config); } spa_close(spa, FTAG); return (error); } /* * inputs: * zc_name name of the pool ! * zc_nvlist_conf nvlist of devices to remove ! * zc_cookie to stop the remove? */ static int zfs_ioc_vdev_remove(zfs_cmd_t *zc) { spa_t *spa; int error; + nvlist_t *event; error = spa_open(zc->zc_name, &spa, FTAG); if (error != 0) return (error); error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + fnvlist_add_uint64(event, "guid", zc->zc_guid); + zfs_event_post(ZPOOL_EC_STATUS, "remove", event); } + spa_close(spa, FTAG); return (error); } static int
*** 1949,1959 **** error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); break; case VDEV_STATE_FAULTED: if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && ! zc->zc_obj != VDEV_AUX_EXTERNAL) zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); break; --- 2120,2131 ---- error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); break; case VDEV_STATE_FAULTED: if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED && ! zc->zc_obj != VDEV_AUX_EXTERNAL && ! zc->zc_obj != VDEV_AUX_OPEN_FAILED) zc->zc_obj = VDEV_AUX_ERR_EXCEEDED; error = vdev_fault(spa, zc->zc_guid, zc->zc_obj); break;
*** 1977,1994 **** --- 2149,2174 ---- zfs_ioc_vdev_attach(zfs_cmd_t *zc) { spa_t *spa; int replacing = zc->zc_cookie; nvlist_t *config; + nvlist_t *event; int error; if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) return (error); if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, zc->zc_iflags, &config)) == 0) { error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + fnvlist_add_nvlist(event, "config", config); + fnvlist_add_int32(event, "replacing", replacing); + zfs_event_post(ZPOOL_EC_STATUS, "attach", event); + } nvlist_free(config); } spa_close(spa, FTAG); return (error);
*** 1997,2012 **** static int zfs_ioc_vdev_detach(zfs_cmd_t *zc) { spa_t *spa; int error; if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) return (error); error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); ! spa_close(spa, FTAG); return (error); } static int --- 2177,2198 ---- static int zfs_ioc_vdev_detach(zfs_cmd_t *zc) { spa_t *spa; int error; + nvlist_t *event; if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) return (error); error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE); ! if (error == 0) { ! event = fnvlist_alloc(); ! fnvlist_add_string(event, "pool", zc->zc_name); ! fnvlist_add_uint64(event, "guid", zc->zc_guid); ! zfs_event_post(ZPOOL_EC_STATUS, "detach", event); ! } spa_close(spa, FTAG); return (error); } static int
*** 2043,2052 **** --- 2229,2256 ---- return (error); } static int + zfs_ioc_vdev_setl2adddt(zfs_cmd_t *zc) + { + spa_t *spa; + int error; + uint64_t guid = zc->zc_guid; + char *l2ad_ddt = zc->zc_value; + + error = spa_open(zc->zc_name, &spa, FTAG); + if (error != 0) + return (error); + + error = spa_vdev_setl2adddt(spa, guid, l2ad_ddt); + spa_close(spa, FTAG); + return (error); + } + + + static int zfs_ioc_vdev_setpath(zfs_cmd_t *zc) { spa_t *spa; char *path = zc->zc_value; uint64_t guid = zc->zc_guid;
*** 2121,2131 **** * zc_nvlist_dst_size size of property nvlist */ static int zfs_ioc_objset_stats(zfs_cmd_t *zc) { ! objset_t *os; int error; error = dmu_objset_hold(zc->zc_name, FTAG, &os); if (error == 0) { error = zfs_ioc_objset_stats_impl(zc, os); --- 2325,2335 ---- * zc_nvlist_dst_size size of property nvlist */ static int zfs_ioc_objset_stats(zfs_cmd_t *zc) { ! objset_t *os = NULL; int error; error = dmu_objset_hold(zc->zc_name, FTAG, &os); if (error == 0) { error = zfs_ioc_objset_stats_impl(zc, os);
*** 2230,2256 **** } dmu_objset_rele(os, FTAG); return (err); } - static boolean_t - dataset_name_hidden(const char *name) - { - /* - * Skip over datasets that are not visible in this zone, - * internal datasets (which have a $ in their name), and - * temporary datasets (which have a % in their name). - */ - if (strchr(name, '$') != NULL) - return (B_TRUE); - if (strchr(name, '%') != NULL) - return (B_TRUE); - if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL)) - return (B_TRUE); - return (B_FALSE); - } - /* * inputs: * zc_name name of filesystem * zc_cookie zap cursor * zc_nvlist_dst_size size of buffer for property nvlist --- 2434,2443 ----
*** 2519,2543 **** --- 2706,2756 ---- */ int zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, nvlist_t *errlist) { + spa_t *spa = NULL; nvpair_t *pair; nvpair_t *propval; int rv = 0; uint64_t intval; char *strval; nvlist_t *genericnvl = fnvlist_alloc(); nvlist_t *retrynvl = fnvlist_alloc(); + zfsvfs_t *zfsvfs; + boolean_t set_worm = B_FALSE; + boolean_t set_wbc_mode = B_FALSE; + boolean_t wbc_walk_locked = B_FALSE; + boolean_t set_dedup = B_FALSE; + if ((rv = spa_open(dsname, &spa, FTAG)) != 0) + return (rv); + retry: pair = NULL; while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { const char *propname = nvpair_name(pair); zfs_prop_t prop = zfs_name_to_prop(propname); int err = 0; + if (!set_worm && (strcmp(propname, "nms:worm") == 0)) { + set_worm = B_TRUE; + } + + /* + * If 'wbc_mode' is going to be changed, then we need to + * do some actions before 'set' + */ + if (prop == ZFS_PROP_WBC_MODE) + set_wbc_mode = B_TRUE; + + /* + * + */ + if (prop == ZFS_PROP_DEDUP) + set_dedup = B_TRUE; + /* decode the property value */ propval = pair; if (nvpair_type(pair) == DATA_TYPE_NVLIST) { nvlist_t *attrs; attrs = fnvpair_value_nvlist(pair);
*** 2619,2628 **** --- 2832,2866 ---- if (nvl != retrynvl && !nvlist_empty(retrynvl)) { nvl = retrynvl; goto retry; } + /* + * Deduplication and WBC cannot be used together + * This code returns error also for case when + * WBC is ON, DEDUP is off and a user tries + * to do DEDUP=off, because in this case the code + * will be more complex, but benefit is too small + */ + if (set_wbc_mode && set_dedup) { + nvlist_free(genericnvl); + nvlist_free(retrynvl); + spa_close(spa, FTAG); + + return (SET_ERROR(EKZFS_WBCCONFLICT)); + } + + /* + * Additional actions before set wbc_mode: + * - first need to try to lock WBC-walking, to stop migration and + * avoid the openning of new migration window + * - second step (from sync-context): if migration window + * is active it will be purged, to correctly add/remove WBC-instance + */ + if (set_wbc_mode && wbc_walk_lock(spa) == 0) + wbc_walk_locked = B_TRUE; + if (!nvlist_empty(genericnvl) && dsl_props_set(dsname, source, genericnvl) != 0) { /* * If this fails, we still want to set as many properties as we * can, so try setting them individually.
*** 2660,2669 **** --- 2898,2924 ---- } } nvlist_free(genericnvl); nvlist_free(retrynvl); + if (wbc_walk_locked) + wbc_walk_unlock(spa); + + if (set_worm && getzfsvfs(dsname, &zfsvfs) == 0) { + if (zfs_is_wormed(dsname)) { + zfsvfs->z_isworm = B_TRUE; + } else { + zfsvfs->z_isworm = B_FALSE; + } + VFS_RELE(zfsvfs->z_vfs); + } + + if (rv == 0) + autosnap_force_snap_by_name(dsname, NULL, B_FALSE); + + spa_close(spa, FTAG); + return (rv); } /* * Check that all the properties are valid user properties.
*** 2687,2697 **** if (strlen(propname) >= ZAP_MAXNAMELEN) return (SET_ERROR(ENAMETOOLONG)); if (strlen(fnvpair_value_string(pair)) >= ZAP_MAXVALUELEN) ! return (E2BIG); } return (0); } static void --- 2942,2952 ---- if (strlen(propname) >= ZAP_MAXNAMELEN) return (SET_ERROR(ENAMETOOLONG)); if (strlen(fnvpair_value_string(pair)) >= ZAP_MAXVALUELEN) ! return (SET_ERROR(E2BIG)); } return (0); } static void
*** 2728,2739 **** --- 2983,3116 ---- } nvlist_free(cleared_props); return (err); } + int + zfs_ioc_set_prop_impl(char *name, nvlist_t *props, + boolean_t received, nvlist_t **out_errors) + { + int error = 0; + nvlist_t *errors, *event; + zprop_source_t source = (received ? ZPROP_SRC_RECEIVED : + ZPROP_SRC_LOCAL); + + ASSERT(props != NULL); + + if (received) { + nvlist_t *origprops; + + if (dsl_prop_get_received(name, &origprops) == 0) { + (void) clear_received_props(name, origprops, props); + nvlist_free(origprops); + } + + error = dsl_prop_set_hasrecvd(name); + } + + errors = fnvlist_alloc(); + if (error == 0) + error = zfs_set_prop_nvlist(name, source, props, errors); + + event = fnvlist_alloc(); + fnvlist_add_string(event, "fsname", name); + fnvlist_add_nvlist(event, "properties", props); + fnvlist_add_nvlist(event, "errors", errors); + zfs_event_post(ZFS_EC_STATUS, "set", event); + + if (out_errors != NULL) + *out_errors = fnvlist_dup(errors); + + fnvlist_free(errors); + + return (error); + } + /* + * XXX This functionality will be removed after integration of + * functionality, that does the same via zfs-channel programm. + * The zfs-channel programm implementation is being developed + * by Delphix. + * + * This functions sets provided props for provided datasets + * in one sync-round. There are some requirements: + * - all datasets should belong to the same pool + * - only user-properties + * + * This function does all or nothing. + * * inputs: + * zc_nvlist_src{_size} nvlist of datasets and properties to apply + * + * outputs: + * zc_nvlist_dst{_size} error for each unapplied property + */ + /* ARGSUSED */ + static int + zfs_ioc_set_prop_mds(const char *pool_name, nvlist_t *dss_props, + nvlist_t *outnvl) + { + int error = 0; + spa_t *spa = NULL; + nvpair_t *pair = NULL; + size_t pool_name_len; + size_t total_num_props = 0; + + ASSERT(dss_props != NULL); + + if (nvlist_empty(dss_props)) + return (SET_ERROR(ENODATA)); + + pool_name_len = strlen(pool_name); + while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) { + nvlist_t *props; + nvpair_t *prop_nvp = NULL; + const char *ds_name; + + ds_name = nvpair_name(pair); + if (strncmp(pool_name, ds_name, pool_name_len) == 0) { + char c = ds_name[pool_name_len]; + if (c != '\0' && c != '/' && c != '@') + return (SET_ERROR(EXDEV)); + } + + if (nvpair_type(pair) != DATA_TYPE_NVLIST) + return (SET_ERROR(EINVAL)); + + props = fnvpair_value_nvlist(pair); + while ((prop_nvp = nvlist_next_nvpair(props, + prop_nvp)) != NULL) { + const char *propname = nvpair_name(prop_nvp); + /* Only user-props */ + if (!zfs_prop_user(propname) || + nvpair_type(prop_nvp) != DATA_TYPE_STRING) + return (SET_ERROR(EINVAL)); + + /* + * We count the number to use it + * later to check for ENOSPC + */ + total_num_props++; + } + } + + if ((error = spa_open(pool_name, &spa, FTAG)) != 0) + return (error); + + error = dsl_props_set_mds(pool_name, dss_props, total_num_props); + spa_close(spa, FTAG); + if (error == 0) { + nvlist_t *event = fnvlist_alloc(); + fnvlist_add_nvlist(event, "properties", dss_props); + zfs_event_post(ZFS_EC_STATUS, "set-mds", event); + } + + return (error); + } + + /* + * inputs: * zc_name name of filesystem * zc_value name of property to set * zc_nvlist_src{_size} nvlist of properties to apply * zc_cookie received properties flag *
*** 2743,2777 **** static int zfs_ioc_set_prop(zfs_cmd_t *zc) { nvlist_t *nvl; boolean_t received = zc->zc_cookie; ! zprop_source_t source = (received ? ZPROP_SRC_RECEIVED : ! ZPROP_SRC_LOCAL); ! nvlist_t *errors; int error; if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, zc->zc_iflags, &nvl)) != 0) return (error); ! if (received) { ! nvlist_t *origprops; - if (dsl_prop_get_received(zc->zc_name, &origprops) == 0) { - (void) clear_received_props(zc->zc_name, - origprops, nvl); - nvlist_free(origprops); - } - - error = dsl_prop_set_hasrecvd(zc->zc_name); - } - - errors = fnvlist_alloc(); - if (error == 0) - error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, errors); - if (zc->zc_nvlist_dst != NULL && errors != NULL) { (void) put_nvlist(zc, errors); } nvlist_free(errors); --- 3120,3138 ---- static int zfs_ioc_set_prop(zfs_cmd_t *zc) { nvlist_t *nvl; boolean_t received = zc->zc_cookie; ! nvlist_t *errors = NULL; int error; if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, zc->zc_iflags, &nvl)) != 0) return (error); ! error = zfs_ioc_set_prop_impl(zc->zc_name, nvl, received, &errors); if (zc->zc_nvlist_dst != NULL && errors != NULL) { (void) put_nvlist(zc, errors); } nvlist_free(errors);
*** 2859,2869 **** { nvlist_t *props; spa_t *spa; int error; nvpair_t *pair; ! if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, zc->zc_iflags, &props)) return (error); /* --- 3220,3230 ---- { nvlist_t *props; spa_t *spa; int error; nvpair_t *pair; ! nvlist_t *event; if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, zc->zc_iflags, &props)) return (error); /*
*** 2875,2885 **** zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && nvlist_next_nvpair(props, pair) == NULL) { mutex_enter(&spa_namespace_lock); if ((spa = spa_lookup(zc->zc_name)) != NULL) { spa_configfile_set(spa, props, B_FALSE); ! spa_write_cachefile(spa, B_FALSE, B_TRUE); } mutex_exit(&spa_namespace_lock); if (spa != NULL) { nvlist_free(props); return (0); --- 3236,3246 ---- zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && nvlist_next_nvpair(props, pair) == NULL) { mutex_enter(&spa_namespace_lock); if ((spa = spa_lookup(zc->zc_name)) != NULL) { spa_configfile_set(spa, props, B_FALSE); ! spa_config_sync(spa, B_FALSE, B_TRUE); } mutex_exit(&spa_namespace_lock); if (spa != NULL) { nvlist_free(props); return (0);
*** 2891,2900 **** --- 3252,3268 ---- return (error); } error = spa_prop_set(spa, props); + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "pool", zc->zc_name); + fnvlist_add_nvlist(event, "props", props); + zfs_event_post(ZPOOL_EC_STATUS, "set", event); + } + nvlist_free(props); spa_close(spa, FTAG); return (error); }
*** 3012,3021 **** --- 3380,3392 ---- #define ZFS_PROP_UNDEFINED ((uint64_t)-1) /* * inputs: + * createprops list of properties requested by creator + * default_zplver zpl version to use if unspecified in createprops + * fuids_ok fuids allowed in this version of the spa? * os parent objset pointer (NULL if root fs) * fuids_ok fuids allowed in this version of the spa? * sa_ok SAs allowed in this version of the spa? * createprops list of properties requested by creator *
*** 3089,3098 **** --- 3460,3474 ---- if (norm == ZFS_PROP_UNDEFINED) VERIFY(zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm) == 0); VERIFY(nvlist_add_uint64(zplprops, zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0); + if (os) { + if (zfs_is_wormed_ds(dmu_objset_ds(os))) + return (SET_ERROR(EPERM)); + } + /* * If we're normalizing, names must always be valid UTF-8 strings. */ if (norm) u8 = 1;
*** 3186,3195 **** --- 3562,3573 ---- nvlist_t *nvprops = NULL; void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); int32_t type32; dmu_objset_type_t type; boolean_t is_insensitive = B_FALSE; + char parent[MAXNAMELEN]; + nvlist_t *event; if (nvlist_lookup_int32(innvl, "type", &type32) != 0) return (SET_ERROR(EINVAL)); type = type32; (void) nvlist_lookup_nvlist(innvl, "props", &nvprops);
*** 3214,3223 **** --- 3592,3606 ---- zct.zct_props = nvprops; if (cbfunc == NULL) return (SET_ERROR(EINVAL)); + if (zfs_get_parent(fsname, parent, MAXNAMELEN) == 0 && + zfs_is_wormed(parent)) { + return (SET_ERROR(EPERM)); + } + if (type == DMU_OST_ZVOL) { uint64_t volsize, volblocksize; if (nvprops == NULL) return (SET_ERROR(EINVAL));
*** 3238,3249 **** volblocksize)) != 0 || (error = zvol_check_volsize(volsize, volblocksize)) != 0) return (error); } else if (type == DMU_OST_ZFS) { - int error; - /* * We have to have normalization and * case-folding flags correct when we do the * file system creation, so go figure them out * now. --- 3621,3630 ----
*** 3269,3278 **** --- 3650,3669 ---- error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, nvprops, outnvl); if (error != 0) (void) dsl_destroy_head(fsname); } + + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "fsname", fsname); + fnvlist_add_int32(event, "type", type); + if (nvprops != NULL) + fnvlist_add_nvlist(event, "properties", nvprops); + zfs_event_post(ZFS_EC_STATUS, "create", event); + } + return (error); } /* * innvl: {
*** 3285,3306 **** static int zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) { int error = 0; nvlist_t *nvprops = NULL; ! char *origin_name; if (nvlist_lookup_string(innvl, "origin", &origin_name) != 0) return (SET_ERROR(EINVAL)); (void) nvlist_lookup_nvlist(innvl, "props", &nvprops); if (strchr(fsname, '@') || strchr(fsname, '%')) return (SET_ERROR(EINVAL)); if (dataset_namecheck(origin_name, NULL, NULL) != 0) return (SET_ERROR(EINVAL)); error = dmu_objset_clone(fsname, origin_name); if (error != 0) return (error); /* --- 3676,3707 ---- static int zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) { int error = 0; nvlist_t *nvprops = NULL; ! char *origin_name, *origin_snap; ! nvlist_t *event; if (nvlist_lookup_string(innvl, "origin", &origin_name) != 0) return (SET_ERROR(EINVAL)); + + origin_snap = strchr(origin_name, '@'); + if (!origin_snap) + return (SET_ERROR(EINVAL)); + + if (autosnap_check_name(origin_snap)) + return (SET_ERROR(EPERM)); + (void) nvlist_lookup_nvlist(innvl, "props", &nvprops); if (strchr(fsname, '@') || strchr(fsname, '%')) return (SET_ERROR(EINVAL)); if (dataset_namecheck(origin_name, NULL, NULL) != 0) return (SET_ERROR(EINVAL)); + error = dmu_objset_clone(fsname, origin_name); if (error != 0) return (error); /*
*** 3310,3331 **** error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, nvprops, outnvl); if (error != 0) (void) dsl_destroy_head(fsname); } - return (error); - } ! /* ARGSUSED */ ! static int ! zfs_ioc_remap(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) ! { ! if (strchr(fsname, '@') || ! strchr(fsname, '%')) ! return (SET_ERROR(EINVAL)); ! return (dmu_objset_remap_indirects(fsname)); } /* * innvl: { * "snaps" -> { snapshot1, snapshot2 } --- 3711,3731 ---- error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, nvprops, outnvl); if (error != 0) (void) dsl_destroy_head(fsname); } ! if (error == 0) { ! event = fnvlist_alloc(); ! fnvlist_add_string(event, "origin", origin_name); ! fnvlist_add_string(event, "fsname", fsname); ! if (nvprops != NULL) ! fnvlist_add_nvlist(event, "properties", nvprops); ! zfs_event_post(ZFS_EC_STATUS, "clone", event); ! } ! return (error); } /* * innvl: { * "snaps" -> { snapshot1, snapshot2 }
*** 3339,3348 **** --- 3739,3749 ---- { nvlist_t *snaps; nvlist_t *props = NULL; int error, poollen; nvpair_t *pair; + nvlist_t *event; (void) nvlist_lookup_nvlist(innvl, "props", &props); if ((error = zfs_check_userprops(poolname, props)) != 0) return (error);
*** 3364,3373 **** --- 3765,3777 ---- */ if (cp == NULL || zfs_component_namecheck(cp + 1, NULL, NULL) != 0) return (SET_ERROR(EINVAL)); + if (autosnap_check_name(cp)) + return (EINVAL); + /* * The snap must be in the specified pool. */ if (strncmp(name, poolname, poollen) != 0 || (name[poollen] != '/' && name[poollen] != '@'))
*** 3382,3391 **** --- 3786,3802 ---- } } } error = dsl_dataset_snapshot(snaps, props, outnvl); + + event = fnvlist_alloc(); + fnvlist_add_nvlist(event, "snaps", snaps); + fnvlist_add_nvlist(event, "errors", outnvl); + fnvlist_add_string(event, "pool", poolname); + zfs_event_post(ZFS_EC_STATUS, "snapshot", event); + return (error); } /* * innvl: "message" -> string
*** 3499,3508 **** --- 3910,3938 ---- } else { dmu_objset_rele(os, FTAG); } } + static int + zfs_destroy_check_autosnap(spa_t *spa, const char *name) + { + const char *snap = strchr(name, '@'); + + if (snap == NULL) + return (EINVAL); + + if (autosnap_check_name(snap)) { + int err = autosnap_check_for_destroy( + spa_get_autosnap(spa), name); + + if (err != 0) + return (EBUSY); + } + + return (0); + } + /* * innvl: { * "snaps" -> { snapshot1, snapshot2 } * (optional boolean) "defer" * }
*** 3515,3535 **** zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) { nvlist_t *snaps; nvpair_t *pair; boolean_t defer; if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) return (SET_ERROR(EINVAL)); defer = nvlist_exists(innvl, "defer"); for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { zfs_unmount_snap(nvpair_name(pair)); } ! return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl)); } /* * Create bookmarks. Bookmark names are of the form <fs>#<bmark>. * All bookmarks must be in the same pool. --- 3945,3996 ---- zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) { nvlist_t *snaps; nvpair_t *pair; boolean_t defer; + int error = 0; + nvlist_t *event; + spa_t *spa; + if (zfs_is_wormed(poolname)) + return (SET_ERROR(EPERM)); + if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0) return (SET_ERROR(EINVAL)); defer = nvlist_exists(innvl, "defer"); + error = spa_open(poolname, &spa, FTAG); + if (spa == NULL) + return (error); + + for (pair = nvlist_next_nvpair(snaps, NULL); + pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { + error = zfs_destroy_check_autosnap(spa, nvpair_name(pair)); + if (error) + fnvlist_add_int32(outnvl, nvpair_name(pair), error); + } + + spa_close(spa, FTAG); + + if (error) + return (error); + for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { zfs_unmount_snap(nvpair_name(pair)); } ! error = dsl_destroy_snapshots_nvl(snaps, defer, outnvl); ! ! if (error == 0) { ! event = fnvlist_alloc(); ! fnvlist_add_nvlist(event, "snaps", snaps); ! fnvlist_add_nvlist(event, "errors", outnvl); ! zfs_event_post(ZFS_EC_STATUS, "destroy_snaps", event); ! } ! ! return (error); } /* * Create bookmarks. Bookmark names are of the form <fs>#<bmark>. * All bookmarks must be in the same pool.
*** 3661,3687 **** /* * inputs: * zc_name name of dataset to destroy * zc_objset_type type of objset * zc_defer_destroy mark for deferred destroy * * outputs: none */ static int zfs_ioc_destroy(zfs_cmd_t *zc) { int err; if (zc->zc_objset_type == DMU_OST_ZFS) zfs_unmount_snap(zc->zc_name); ! if (strchr(zc->zc_name, '@')) ! err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy); ! else err = dsl_destroy_head(zc->zc_name); if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0) (void) zvol_remove_minor(zc->zc_name); return (err); } /* * fsname is name of dataset to rollback (to most recent snapshot) --- 4122,4230 ---- /* * inputs: * zc_name name of dataset to destroy * zc_objset_type type of objset * zc_defer_destroy mark for deferred destroy + * zc_guid if set, do atomical recursive destroy * * outputs: none */ static int zfs_ioc_destroy(zfs_cmd_t *zc) { int err; + nvlist_t *event; + if (zfs_is_wormed(zc->zc_name)) + return (SET_ERROR(EPERM)); + if (zc->zc_objset_type == DMU_OST_ZFS) zfs_unmount_snap(zc->zc_name); ! if (zc->zc_guid) { ! spa_t *spa; ! ! if ((err = spa_open(zc->zc_name, &spa, FTAG)) != 0) ! return (err); ! ! err = autosnap_lock(spa, RW_WRITER); ! if (err == 0) { ! err = wbc_walk_lock(spa); ! if (err != 0) ! autosnap_unlock(spa); ! } ! ! if (err == 0) { ! err = dsl_destroy_atomically(zc->zc_name, ! zc->zc_defer_destroy); ! wbc_walk_unlock(spa); ! autosnap_unlock(spa); ! } ! ! spa_close(spa, FTAG); ! } else { ! if (strchr(zc->zc_name, '@')) { ! spa_t *spa = NULL; ! ! err = spa_open(zc->zc_name, &spa, FTAG); ! if (err != 0) ! return (err); ! ! err = zfs_destroy_check_autosnap(spa, zc->zc_name); ! if (err == 0) { ! err = dsl_destroy_snapshot(zc->zc_name, ! zc->zc_defer_destroy); ! } ! ! spa_close(spa, FTAG); ! } else { err = dsl_destroy_head(zc->zc_name); + if (err == EEXIST) { + /* + * It is possible that the given DS may have + * hidden child (%recv) datasets - "leftovers" + * resulting from the previously interrupted + * 'zfs receive'. + */ + char namebuf[ZFS_MAX_DATASET_NAME_LEN]; + + if (snprintf(namebuf, sizeof (namebuf), + "%s/%%recv", zc->zc_name) >= + sizeof (namebuf)) + return (err); + + /* Try to remove the hidden child (%recv) */ + err = dsl_destroy_head(namebuf); + if (err == 0) { + /* + * Now the given DS should not have + * children, so we can try to remove + * it again + */ + err = dsl_destroy_head(zc->zc_name); + } else if (err == ENOENT) { + /* + * The hidden child (%recv) does not + * exist, so need to restore original + * error + */ + err = EEXIST; + } + + } + } + } if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0) (void) zvol_remove_minor(zc->zc_name); + + if (err == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "fsname", zc->zc_name); + fnvlist_add_int32(event, "type", zc->zc_objset_type); + zfs_event_post(ZFS_EC_STATUS, "destroy", event); + } + return (err); } /* * fsname is name of dataset to rollback (to most recent snapshot)
*** 3696,3706 **** --- 4239,4254 ---- zfs_ioc_rollback(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) { zfsvfs_t *zfsvfs; char *target = NULL; int error; + nvlist_t *event; + int resume_err = 0; + if (zfs_is_wormed(fsname)) + return (SET_ERROR(EPERM)); + (void) nvlist_lookup_string(innvl, "target", &target); if (target != NULL) { const char *cp = strchr(target, '@'); /*
*** 3716,3736 **** dsl_dataset_t *ds; ds = dmu_objset_ds(zfsvfs->z_os); error = zfs_suspend_fs(zfsvfs); if (error == 0) { - int resume_err; - error = dsl_dataset_rollback(fsname, target, zfsvfs, outnvl); resume_err = zfs_resume_fs(zfsvfs, ds); - error = error ? error : resume_err; } VFS_RELE(zfsvfs->z_vfs); } else { error = dsl_dataset_rollback(fsname, target, NULL, outnvl); } return (error); } static int recursive_unmount(const char *fsname, void *arg) --- 4264,4291 ---- dsl_dataset_t *ds; ds = dmu_objset_ds(zfsvfs->z_os); error = zfs_suspend_fs(zfsvfs); if (error == 0) { error = dsl_dataset_rollback(fsname, target, zfsvfs, outnvl); resume_err = zfs_resume_fs(zfsvfs, ds); } VFS_RELE(zfsvfs->z_vfs); } else { error = dsl_dataset_rollback(fsname, target, NULL, outnvl); } + + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "target", (target != NULL) ? target : ""); + fnvlist_add_string(event, "fsname", fsname); + fnvlist_add_int32(event, "resume_err", resume_err); + zfs_event_post(ZFS_EC_STATUS, "rollback", event); + } + + error = (error != 0) ? error : resume_err; return (error); } static int recursive_unmount(const char *fsname, void *arg)
*** 3755,3777 **** static int zfs_ioc_rename(zfs_cmd_t *zc) { boolean_t recursive = zc->zc_cookie & 1; char *at; ! /* "zfs rename" from and to ...%recv datasets should both fail */ ! zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; ! if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 || ! dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || ! strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%')) return (SET_ERROR(EINVAL)); at = strchr(zc->zc_name, '@'); if (at != NULL) { /* snaps must be in same fs */ - int error; if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) return (SET_ERROR(EXDEV)); *at = '\0'; if (zc->zc_objset_type == DMU_OST_ZFS) { --- 4310,4333 ---- static int zfs_ioc_rename(zfs_cmd_t *zc) { boolean_t recursive = zc->zc_cookie & 1; char *at; + nvlist_t *event; + int error; ! if (zfs_is_wormed(zc->zc_name)) ! return (SET_ERROR(EPERM)); ! zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; ! if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || ! strchr(zc->zc_value, '%')) return (SET_ERROR(EINVAL)); at = strchr(zc->zc_name, '@'); if (at != NULL) { /* snaps must be in same fs */ if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) return (SET_ERROR(EXDEV)); *at = '\0'; if (zc->zc_objset_type == DMU_OST_ZFS) {
*** 3785,3800 **** } error = dsl_dataset_rename_snapshot(zc->zc_name, at + 1, strchr(zc->zc_value, '@') + 1, recursive); *at = '@'; - return (error); } else { if (zc->zc_objset_type == DMU_OST_ZVOL) (void) zvol_remove_minor(zc->zc_name); ! return (dsl_dir_rename(zc->zc_name, zc->zc_value)); } } static int zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) { --- 4341,4365 ---- } error = dsl_dataset_rename_snapshot(zc->zc_name, at + 1, strchr(zc->zc_value, '@') + 1, recursive); *at = '@'; } else { if (zc->zc_objset_type == DMU_OST_ZVOL) (void) zvol_remove_minor(zc->zc_name); ! error = dsl_dir_rename(zc->zc_name, zc->zc_value); } + + if (error == 0) { + event = fnvlist_alloc(); + fnvlist_add_string(event, "origin", zc->zc_name); + fnvlist_add_string(event, "fsname", zc->zc_value); + fnvlist_add_int32(event, "type", zc->zc_objset_type); + zfs_event_post(ZFS_EC_STATUS, "rename", event); + } + + return (error); } static int zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) {
*** 3947,3956 **** --- 4512,4547 ---- SPA_VERSION_PASSTHROUGH_X)) return (SET_ERROR(ENOTSUP)); } break; + case ZFS_PROP_WBC_MODE: + { + spa_t *spa; + boolean_t wbc_feature_enabled; + + if ((err = spa_open(dsname, &spa, FTAG)) != 0) + return (err); + + wbc_feature_enabled = + spa_feature_is_enabled(spa, SPA_FEATURE_WBC); + spa_close(spa, FTAG); + + /* WBC cannot be used without special-vdev */ + if (!wbc_feature_enabled || !spa_has_special(spa)) + return (SET_ERROR(EKZFS_WBCNOTSUP)); + + /* + * We do not want to have races, because on + * import or after reboot WBC does registration + * asynchronously. + */ + if (!spa->spa_wbc.wbc_ready_to_use) + return (SET_ERROR(EBUSY)); + } + break; + case ZFS_PROP_CHECKSUM: case ZFS_PROP_DEDUP: { spa_feature_t feature; spa_t *spa;
*** 4222,4300 **** #ifdef DEBUG static boolean_t zfs_ioc_recv_inject_err; #endif ! /* ! * inputs: ! * zc_name name of containing filesystem ! * zc_nvlist_src{_size} nvlist of properties to apply ! * zc_value name of snapshot to create ! * zc_string name of clone origin (if DRR_FLAG_CLONE) ! * zc_cookie file descriptor to recv from ! * zc_begin_record the BEGIN record of the stream (not byteswapped) ! * zc_guid force flag ! * zc_cleanup_fd cleanup-on-exit file descriptor ! * zc_action_handle handle for this guid/ds mapping (or zero on first call) ! * zc_resumable if data is incomplete assume sender will resume ! * ! * outputs: ! * zc_cookie number of bytes read ! * zc_nvlist_dst{_size} error for each unapplied received property ! * zc_obj zprop_errflags_t ! * zc_action_handle handle for this guid/ds mapping ! */ ! static int ! zfs_ioc_recv(zfs_cmd_t *zc) { ! file_t *fp; dmu_recv_cookie_t drc; - boolean_t force = (boolean_t)zc->zc_guid; - int fd; int error = 0; int props_error = 0; - nvlist_t *errors; offset_t off; - nvlist_t *props = NULL; /* sent properties */ nvlist_t *origprops = NULL; /* existing properties */ nvlist_t *delayprops = NULL; /* sent properties applied post-receive */ - char *origin = NULL; - char *tosnap; - char tofs[ZFS_MAX_DATASET_NAME_LEN]; boolean_t first_recvd_props = B_FALSE; ! if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || ! strchr(zc->zc_value, '@') == NULL || ! strchr(zc->zc_value, '%')) ! return (SET_ERROR(EINVAL)); - (void) strcpy(tofs, zc->zc_value); - tosnap = strchr(tofs, '@'); - *tosnap++ = '\0'; - - if (zc->zc_nvlist_src != NULL && - (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, - zc->zc_iflags, &props)) != 0) - return (error); - - fd = zc->zc_cookie; - fp = getf(fd); - if (fp == NULL) { - nvlist_free(props); - return (SET_ERROR(EBADF)); - } - - errors = fnvlist_alloc(); - - if (zc->zc_string[0]) - origin = zc->zc_string; - error = dmu_recv_begin(tofs, tosnap, ! &zc->zc_begin_record, force, zc->zc_resumable, origin, &drc); if (error != 0) goto out; /* * Set properties before we receive the stream so that they are applied * to the new data. Note that we must call dmu_recv_stream() if * dmu_recv_begin() succeeds. */ --- 4813,4849 ---- #ifdef DEBUG static boolean_t zfs_ioc_recv_inject_err; #endif ! int ! dmu_recv_impl(int fd, char *tofs, char *tosnap, char *origin, ! dmu_replay_record_t *drr_begin, boolean_t is_resumable, nvlist_t *props, ! nvlist_t *errors, uint64_t *errf, int cfd, uint64_t *ahdl, uint64_t *sz, ! boolean_t force, dmu_krrp_task_t *krrp_task) { ! file_t *fp = getf(fd); dmu_recv_cookie_t drc; int error = 0; int props_error = 0; offset_t off; nvlist_t *origprops = NULL; /* existing properties */ nvlist_t *delayprops = NULL; /* sent properties applied post-receive */ boolean_t first_recvd_props = B_FALSE; + nvlist_t *event; + boolean_t force_cksum = + !krrp_task || krrp_task->buffer_args.force_cksum; ! ASSERT(fp || krrp_task); error = dmu_recv_begin(tofs, tosnap, ! drr_begin, force, is_resumable, force_cksum, origin, &drc); ! if (error != 0) goto out; + drc.drc_krrp_task = krrp_task; /* * Set properties before we receive the stream so that they are applied * to the new data. Note that we must call dmu_recv_stream() if * dmu_recv_begin() succeeds. */
*** 4325,4337 **** (void) nvlist_merge(errors, errlist, 0); nvlist_free(errlist); if (clear_received_props(tofs, origprops, first_recvd_props ? NULL : props) != 0) ! zc->zc_obj |= ZPROP_ERR_NOCLEAR; } else { ! zc->zc_obj |= ZPROP_ERR_NOCLEAR; } } if (props != NULL) { props_error = dsl_prop_set_hasrecvd(tofs); --- 4874,4886 ---- (void) nvlist_merge(errors, errlist, 0); nvlist_free(errlist); if (clear_received_props(tofs, origprops, first_recvd_props ? NULL : props) != 0) ! *errf |= ZPROP_ERR_NOCLEAR; } else { ! *errf |= ZPROP_ERR_NOCLEAR; } } if (props != NULL) { props_error = dsl_prop_set_hasrecvd(tofs);
*** 4341,4358 **** (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, props, errors); } } off = fp->f_offset; ! error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd, ! &zc->zc_action_handle); if (error == 0) { zfsvfs_t *zfsvfs = NULL; ! if (getzfsvfs(tofs, &zfsvfs) == 0) { /* online recv */ dsl_dataset_t *ds; int end_err; ds = dmu_objset_ds(zfsvfs->z_os); --- 4890,4912 ---- (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, props, errors); } } + if (fp) { off = fp->f_offset; ! } else { ! off = 0; ! } ! error = dmu_recv_stream(&drc, fp ? fp->f_vnode : NULL, ! &off, cfd, ahdl, krrp_task); if (error == 0) { zfsvfs_t *zfsvfs = NULL; ! error = getzfsvfs(tofs, &zfsvfs); ! if (error == 0) { /* online recv */ dsl_dataset_t *ds; int end_err; ds = dmu_objset_ds(zfsvfs->z_os);
*** 4389,4416 **** */ ASSERT(nvlist_merge(props, delayprops, 0) == 0); nvlist_free(delayprops); } ! /* ! * Now that all props, initial and delayed, are set, report the prop ! * errors to the caller. ! */ ! if (zc->zc_nvlist_dst_size != 0 && ! (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 || ! put_nvlist(zc, errors) != 0)) { ! /* ! * Caller made zc->zc_nvlist_dst less than the minimum expected ! * size or supplied an invalid address. ! */ ! props_error = SET_ERROR(EINVAL); ! } ! ! zc->zc_cookie = off - fp->f_offset; if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) fp->f_offset = off; #ifdef DEBUG if (zfs_ioc_recv_inject_err) { zfs_ioc_recv_inject_err = B_FALSE; error = 1; } --- 4943,4976 ---- */ ASSERT(nvlist_merge(props, delayprops, 0) == 0); nvlist_free(delayprops); } ! if (fp) { ! *sz = off - fp->f_offset; if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) fp->f_offset = off; + } else { + *sz = off; + } + if (error == 0) { + char val[MAXNAMELEN]; + (void) strcpy(val, tofs); + (void) strcat(val, "@"); + (void) strcat(val, tosnap); + + event = fnvlist_alloc(); + if (props != NULL) + fnvlist_add_nvlist(event, "props", props); + fnvlist_add_string(event, "origin", tofs); + fnvlist_add_string(event, "tosnap", val); + fnvlist_add_uint64(event, "bytes", *sz); + fnvlist_add_boolean_value(event, "newds", drc.drc_newfs); + zfs_event_post(ZFS_EC_STATUS, "recv", event); + } + #ifdef DEBUG if (zfs_ioc_recv_inject_err) { zfs_ioc_recv_inject_err = B_FALSE; error = 1; }
*** 4423,4440 **** /* * We failed to clear the received properties. * Since we may have left a $recvd value on the * system, we can't clear the $hasrecvd flag. */ ! zc->zc_obj |= ZPROP_ERR_NORESTORE; } else if (first_recvd_props) { dsl_prop_unset_hasrecvd(tofs); } if (origprops == NULL && !drc.drc_newfs) { /* We failed to stash the original properties. */ ! zc->zc_obj |= ZPROP_ERR_NORESTORE; } /* * dsl_props_set() will not convert RECEIVED to LOCAL on or * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL --- 4983,5000 ---- /* * We failed to clear the received properties. * Since we may have left a $recvd value on the * system, we can't clear the $hasrecvd flag. */ ! *errf |= ZPROP_ERR_NORESTORE; } else if (first_recvd_props) { dsl_prop_unset_hasrecvd(tofs); } if (origprops == NULL && !drc.drc_newfs) { /* We failed to stash the original properties. */ ! *errf |= ZPROP_ERR_NORESTORE; } /* * dsl_props_set() will not convert RECEIVED to LOCAL on or * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL
*** 4447,4463 **** origprops, NULL) != 0) { /* * We stashed the original properties but failed to * restore them. */ ! zc->zc_obj |= ZPROP_ERR_NORESTORE; } } out: - nvlist_free(props); nvlist_free(origprops); ! nvlist_free(errors); releasef(fd); if (error == 0) error = props_error; --- 5007,5022 ---- origprops, NULL) != 0) { /* * We stashed the original properties but failed to * restore them. */ ! *errf |= ZPROP_ERR_NORESTORE; } } out: nvlist_free(origprops); ! if (fp) releasef(fd); if (error == 0) error = props_error;
*** 4464,4473 **** --- 5023,5107 ---- return (error); } /* * inputs: + * zc_name name of containing filesystem + * zc_nvlist_src{_size} nvlist of properties to apply + * zc_value name of snapshot to create + * zc_string name of clone origin (if DRR_FLAG_CLONE) + * zc_cookie file descriptor to recv from + * zc_begin_record the BEGIN record of the stream (not byteswapped) + * zc_guid force flag + * zc_cleanup_fd cleanup-on-exit file descriptor + * zc_action_handle handle for this guid/ds mapping (or zero on first call) + * zc_resumable if data is incomplete assume sender will resume + * + * outputs: + * zc_cookie number of bytes read + * zc_nvlist_dst{_size} error for each unapplied received property + * zc_obj zprop_errflags_t + * zc_action_handle handle for this guid/ds mapping + */ + static int + zfs_ioc_recv(zfs_cmd_t *zc) + { + int fd = zc->zc_cookie; + char tofs[ZFS_MAX_DATASET_NAME_LEN]; + char *tosnap; + char *origin = NULL; + nvlist_t *errors; + nvlist_t *props = NULL; /* sent properties */ + boolean_t force = (boolean_t)zc->zc_guid; + int err; + + if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || + strchr(zc->zc_value, '@') == NULL || + strchr(zc->zc_value, '%')) + return (SET_ERROR(EINVAL)); + + (void) strcpy(tofs, zc->zc_value); + tosnap = strchr(tofs, '@'); + *tosnap++ = '\0'; + + if (zc->zc_string[0]) + origin = zc->zc_string; + + if (zc->zc_nvlist_src != NULL && + (err = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, + zc->zc_iflags, &props)) != 0) + return (err); + + errors = fnvlist_alloc(); + + err = dmu_recv_impl(fd, tofs, tosnap, origin, + &zc->zc_begin_record, zc->zc_resumable, props, errors, &zc->zc_obj, + zc->zc_cleanup_fd, &zc->zc_action_handle, &zc->zc_cookie, + force, NULL); + + /* + * Now that all props, initial and delayed, are set, report the prop + * errors to the caller. + */ + if (zc->zc_nvlist_dst_size != 0 && + (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 || + put_nvlist(zc, errors) != 0)) { + /* + * Caller made zc->zc_nvlist_dst less than the minimum expected + * size or supplied an invalid address. + */ + err = SET_ERROR(EINVAL); + } + + nvlist_free(errors); + nvlist_free(props); + return (err); + + } + + /* + * inputs: * zc_name name of snapshot to send * zc_cookie file descriptor to send stream to * zc_obj fromorigin flag (mutually exclusive with zc_fromobj) * zc_sendobj objsetid of snapshot to send * zc_fromobj objsetid of incremental fromsnap (may be zero)
*** 4540,4558 **** if (fromsnap != NULL) dsl_dataset_rele(fromsnap, FTAG); dsl_dataset_rele(tosnap, FTAG); dsl_pool_rele(dp, FTAG); } else { file_t *fp = getf(zc->zc_cookie); if (fp == NULL) return (SET_ERROR(EBADF)); ! off = fp->f_offset; error = dmu_send_obj(zc->zc_name, zc->zc_sendobj, zc->zc_fromobj, embedok, large_block_ok, compressok, ! zc->zc_cookie, fp->f_vnode, &off); if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) fp->f_offset = off; releasef(zc->zc_cookie); } return (error); --- 5174,5194 ---- if (fromsnap != NULL) dsl_dataset_rele(fromsnap, FTAG); dsl_dataset_rele(tosnap, FTAG); dsl_pool_rele(dp, FTAG); } else { + offset_t off_starting; file_t *fp = getf(zc->zc_cookie); if (fp == NULL) return (SET_ERROR(EBADF)); ! off_starting = off = fp->f_offset; error = dmu_send_obj(zc->zc_name, zc->zc_sendobj, zc->zc_fromobj, embedok, large_block_ok, compressok, ! zc->zc_cookie, fp->f_vnode, &off, zc->zc_sendsize); + zc->zc_sendcounter = off - off_starting; if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) fp->f_offset = off; releasef(zc->zc_cookie); } return (error);
*** 4783,4798 **** dsl_pool_t *dp; dsl_dataset_t *ds, *ods; char origin[ZFS_MAX_DATASET_NAME_LEN]; char *cp; int error; - zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; - if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 || - strchr(zc->zc_name, '%')) - return (SET_ERROR(EINVAL)); - error = dsl_pool_hold(zc->zc_name, FTAG, &dp); if (error != 0) return (error); error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds); --- 5419,5430 ---- dsl_pool_t *dp; dsl_dataset_t *ds, *ods; char origin[ZFS_MAX_DATASET_NAME_LEN]; char *cp; int error; + nvlist_t *event; error = dsl_pool_hold(zc->zc_name, FTAG, &dp); if (error != 0) return (error); error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds);
*** 4827,4837 **** cp = strchr(origin, '@'); if (cp) *cp = '\0'; (void) dmu_objset_find(origin, zfs_unmount_snap_cb, NULL, DS_FIND_SNAPSHOTS); ! return (dsl_dataset_promote(zc->zc_name, zc->zc_string)); } /* * Retrieve a single {user|group}{used|quota}@... property. * --- 5459,5478 ---- cp = strchr(origin, '@'); if (cp) *cp = '\0'; (void) dmu_objset_find(origin, zfs_unmount_snap_cb, NULL, DS_FIND_SNAPSHOTS); ! error = dsl_dataset_promote(zc->zc_name, zc->zc_string); ! ! if (error == 0) { ! event = fnvlist_alloc(); ! fnvlist_add_string(event, "fsname", zc->zc_name); ! fnvlist_add_string(event, "origin", zc->zc_value); ! zfs_event_post(ZFS_EC_STATUS, "promote", event); ! } ! ! return (error); } /* * Retrieve a single {user|group}{used|quota}@... property. *
*** 5508,5517 **** --- 6149,6365 ---- fnvlist_add_uint64(outnvl, "compressed", comp); fnvlist_add_uint64(outnvl, "uncompressed", uncomp); return (error); } + static int + zfs_ioc_vdev_set_props(zfs_cmd_t *zc) + { + nvlist_t *props; + spa_t *spa; + int error; + uint64_t vdev_guid = zc->zc_guid; + + if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, + zc->zc_iflags, &props)) + return (error); + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { + nvlist_free(props); + return (error); + } + + error = spa_vdev_prop_set(spa, vdev_guid, props); + + nvlist_free(props); + spa_close(spa, FTAG); + + return (error); + } + + static int + zfs_ioc_vdev_get_props(zfs_cmd_t *zc) + { + spa_t *spa; + uint64_t vdev_guid = zc->zc_guid; + nvlist_t *nvp = NULL; + int error; + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { + /* + * If the pool is faulted, there may be properties we can still + * get (such as altroot and cachefile), so attempt to get them + * anyway. + */ + mutex_enter(&spa_namespace_lock); + if ((spa = spa_lookup(zc->zc_name)) != NULL) + error = spa_vdev_prop_get(spa, vdev_guid, &nvp); + mutex_exit(&spa_namespace_lock); + } else { + error = spa_vdev_prop_get(spa, vdev_guid, &nvp); + spa_close(spa, FTAG); + } + + if (error == 0 && zc->zc_nvlist_dst != NULL) + error = put_nvlist(zc, nvp); + else + error = EFAULT; + + nvlist_free(nvp); + return (error); + } + + static int + zfs_ioc_cos_alloc(zfs_cmd_t *zc) + { + nvlist_t *props; + spa_t *spa; + int error; + + if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, + zc->zc_iflags, &props)) + return (error); + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { + nvlist_free(props); + return (error); + } + + error = spa_alloc_cos(spa, zc->zc_string, 0); + if (!error) + error = spa_cos_prop_set(spa, zc->zc_string, props); + + spa_close(spa, FTAG); + nvlist_free(props); + + return (error); + } + + static int + zfs_ioc_cos_free(zfs_cmd_t *zc) + { + spa_t *spa; + int error = 0; + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) + return (error); + + error = spa_free_cos(spa, zc->zc_string, zc->zc_cookie); + + spa_close(spa, FTAG); + + return (error); + } + + static int + zfs_ioc_cos_list(zfs_cmd_t *zc) + { + spa_t *spa; + nvlist_t *nvl; + int error = 0; + + VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0); + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { + nvlist_free(nvl); + return (error); + } + + error = spa_list_cos(spa, nvl); + + if (error == 0 && zc->zc_nvlist_dst != NULL) + error = put_nvlist(zc, nvl); + + spa_close(spa, FTAG); + nvlist_free(nvl); + + return (error); + } + + static int + zfs_ioc_cos_set_props(zfs_cmd_t *zc) + { + nvlist_t *props; + spa_t *spa; + cos_t *cos; + const char *cosname = NULL; + int error = 0; + + if ((zc->zc_string == NULL || zc->zc_string[0] == '\0') && + zc->zc_guid == 0) + return (SET_ERROR(EINVAL)); + + if (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, + zc->zc_iflags, &props)) + return (error); + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { + nvlist_free(props); + return (error); + } + + if (zc->zc_guid == 0) { + cosname = zc->zc_string; + } else { + spa_cos_enter(spa); + cos = spa_lookup_cos_by_guid(spa, zc->zc_guid); + if (cos != NULL) + cosname = cos->cos_name; + else + error = SET_ERROR(ENOENT); + spa_cos_exit(spa); + } + + if (error == 0) + error = spa_cos_prop_set(spa, cosname, props); + + spa_close(spa, FTAG); + nvlist_free(props); + + return (error); + } + + static int + zfs_ioc_cos_get_props(zfs_cmd_t *zc) + { + spa_t *spa; + cos_t *cos; + nvlist_t *nvp = NULL; + const char *cosname = NULL; + int error = 0; + + if ((zc->zc_string == NULL || zc->zc_string[0] == '\0') && + zc->zc_guid == 0) + return (SET_ERROR(EINVAL)); + + if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) + return (error); + + if (zc->zc_guid == 0) { + cosname = zc->zc_string; + } else { + spa_cos_enter(spa); + cos = spa_lookup_cos_by_guid(spa, zc->zc_guid); + if (cos != NULL) + cosname = cos->cos_name; + spa_cos_exit(spa); + } + + if (error == 0) + error = spa_cos_prop_get(spa, cosname, &nvp); + + spa_close(spa, FTAG); + + if (error == 0 && zc->zc_nvlist_dst != NULL) + error = put_nvlist(zc, nvp); + else + error = EFAULT; + + nvlist_free(nvp); + return (error); + } + /* * innvl: { * "fd" -> file descriptor to write stream to (int32) * (optional) "fromsnap" -> full snap name to send an incremental from * (optional) "largeblockok" -> (value ignored)
*** 5658,5667 **** --- 6506,6729 ---- dsl_dataset_rele(tosnap, FTAG); dsl_pool_rele(dp, FTAG); return (error); } + typedef struct dp_cursor_cb_arg { + nvlist_t *outnvl; + uint64_t offset; + uint32_t count; + uint32_t skip; + boolean_t verbose; + boolean_t snaps; + } dp_cursor_cb_arg_t; + + /* ARGSUSED */ + int + ds_cursor_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) + { + int error; + char dsname[MAXNAMELEN]; + objset_t *osp; + + dp_cursor_cb_arg_t *cb = (dp_cursor_cb_arg_t *)arg; + + dsl_dataset_name(ds, dsname); + nvlist_t *nv = fnvlist_alloc(); + + fnvlist_add_uint64(nv, zfs_prop_to_name(ZFS_PROP_GUID), + dsl_dataset_phys(ds)->ds_guid); + + if (cb->verbose) { + uint64_t refd, avail, uobjs, aobjs; + dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); + + fnvlist_add_uint64(nv, zfs_prop_to_name(ZFS_PROP_AVAILABLE), + avail); + fnvlist_add_uint64(nv, zfs_prop_to_name(ZFS_PROP_REFERENCED), + refd); + fnvlist_add_uint64(nv, zfs_prop_to_name(ZFS_PROP_USED), + dsl_dir_phys(ds->ds_dir)->dd_used_bytes); + } + + error = dmu_objset_from_ds(ds, &osp); + + if (error == 0) + fnvlist_add_uint64(nv, zfs_prop_to_name(ZFS_PROP_TYPE), + dmu_objset_type(osp)); + + fnvlist_add_nvlist(cb->outnvl, dsname, nv); + nvlist_free(nv); + return (error); + } + + int + dmu_objset_find_dp_cursor(dsl_pool_t *dp, uint64_t ddobj, + int func(dsl_pool_t *, dsl_dataset_t *, void *), void *arg) + { + dsl_dir_t *dd; + dsl_dataset_t *ds; + zap_cursor_t zc; + zap_attribute_t *attr; + uint64_t thisobj; + int error, i; + + dp_cursor_cb_arg_t *cb = (dp_cursor_cb_arg_t *)arg; + + ASSERT(dsl_pool_config_held(dp)); + error = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd); + thisobj = dsl_dir_phys(dd)->dd_head_dataset_obj; + + if (error != 0) + return (error); + + attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); + + /* we are interrestd in filesytems and volumes */ + if (!cb->snaps) { + + /* init the cursor at given offset */ + zap_cursor_init_serialized(&zc, dp->dp_meta_objset, + dsl_dir_phys(dd)->dd_child_dir_zapobj, cb->offset); + + + for (i = 0; i < cb->skip; i++) { + zap_cursor_advance(&zc); + if ((zap_cursor_retrieve(&zc, attr) != 0)) { + error = ENOENT; + goto out; + } + } + + for (i = 0; i < cb->count; i++) { + zap_cursor_advance(&zc); + if ((zap_cursor_retrieve(&zc, attr) != 0)) { + error = ENOENT; + goto out; + } + + ASSERT3U(attr->za_integer_length, ==, + sizeof (uint64_t)); + ASSERT3U(attr->za_num_integers, ==, 1); + /* recursivly walk objects skipping $MOS and $ORIGIN */ + error = dmu_objset_find_dp(dp, attr->za_first_integer, + func, arg, 0); + if (error != 0) + break; + } + } else { + + dsl_dataset_t *ds; + + error = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); + + if (error == 0) { + + dsl_dataset_rele(ds, FTAG); + zap_cursor_init_serialized(&zc, dp->dp_meta_objset, + dsl_dataset_phys(ds)->ds_snapnames_zapobj, + cb->offset); + + for (i = 0; i < cb->skip; i++) { + zap_cursor_advance(&zc); + if ((zap_cursor_retrieve(&zc, + attr) != 0)) { + error = ENOENT; + goto out; + } + } + + for (i = 0; i < cb->count; i++) { + zap_cursor_advance(&zc); + if ((zap_cursor_retrieve(&zc, attr) != 0)) { + error = ENOENT; + goto out; + + } + + ASSERT3U(attr->za_integer_length, ==, + sizeof (uint64_t)); + ASSERT3U(attr->za_num_integers, ==, 1); + + error = dsl_dataset_hold_obj(dp, + attr->za_first_integer, FTAG, &ds); + if (error != 0) + break; + error = func(dp, ds, arg); + dsl_dataset_rele(ds, FTAG); + if (error != 0) + break; + } + } + } + out: + cb->offset = zap_cursor_serialize(&zc); + zap_cursor_fini(&zc); + dsl_dir_rele(dd, FTAG); + kmem_free(attr, sizeof (zap_attribute_t)); + + /* return self as the last dataset */ + if (error == ENOENT) { + if ((error = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds)) != 0) + return (error); + error = func(dp, ds, arg); + dsl_dataset_rele(ds, FTAG); + if (error) + return (error); + error = ENOENT; + } + + return (error); + } + + + /* + * We want to list all dataset under the given name. Optionally, we advance the + * ZAP cursor "skip" times and retrieve "count" datasets. We return the offset + * so the user can start the next invocation where he left off. + */ + + static int + zfs_ioc_list_from_cursor(const char *name, nvlist_t *innvl, nvlist_t *outnvl) + { + + dsl_pool_t *dp; + dsl_dataset_t *ds; + + int error; + + dp_cursor_cb_arg_t cb_args; + + if ((strchr(name, '@') != NULL)) + return (EINVAL); + + if ((error = dsl_pool_hold(name, FTAG, &dp)) != 0) + return (error); + + if ((error = dsl_dataset_hold(dp, name, FTAG, &ds)) != 0) { + dsl_pool_rele(dp, FTAG); + return (error); + } + + (void) nvlist_lookup_uint32(innvl, "count", &cb_args.count); + (void) nvlist_lookup_uint32(innvl, "skip", &cb_args.skip); + (void) nvlist_lookup_uint64(innvl, "offset", &cb_args.offset); + (void) nvlist_lookup_boolean_value(innvl, "verbose", &cb_args.verbose); + (void) nvlist_lookup_boolean_value(innvl, "snaps", &cb_args.snaps); + + cb_args.outnvl = outnvl; + error = dmu_objset_find_dp_cursor(dp, ds->ds_dir->dd_object, + &ds_cursor_cb, &cb_args); + + fnvlist_add_uint64(outnvl, "offset", cb_args.offset); + dsl_dataset_rele(ds, FTAG); + dsl_pool_rele(dp, FTAG); + + return (error); + } + + static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST]; static void zfs_ioctl_register_legacy(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func, zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
*** 5763,5775 **** --- 6825,7196 ---- { zfs_ioctl_register_legacy(ioc, func, secpolicy, DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); } + /* + * Appearing to take poolname as a parameter is a concession to the ioctl + * handler. Leading underbar for generation idea nvpair exists only on output to + * avoid pool name conflict. + */ + /* ARGSUSED */ + static int + zfs_ioc_pool_configs_nvl(const char *poolname, nvlist_t *innvl, + nvlist_t *outnvl) + { + nvlist_t *configs; + uint64_t generation; + + if (nvlist_lookup_uint64(innvl, "generation", &generation) != 0) + return (SET_ERROR(EINVAL)); + + if ((configs = spa_all_configs(&generation)) == NULL) + return (SET_ERROR(EEXIST)); + + fnvlist_merge(outnvl, configs); + nvlist_free(configs); + fnvlist_add_uint64(outnvl, "_generation", generation); + + return (0); + } + + /* + * Ask spa for pool statistics. If we get a non-NULL config but a non-zero + * return from spa, we return EAGAIN to hint to callers that we've retrieved + * a config for a faulted pool. We take no arguments but declare otherwise to + * suit the ioctl handler's pattern. Similar considerations apply to outnvl as a + * single pointer that has to be merged with config allocated or nulled by spa. + */ + static int + zfs_ioc_pool_stats_nvl(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) + { + nvlist_t *config; + int error; + int ret = 0; + + ASSERT3P(innvl, ==, NULL); + error = spa_get_stats(poolname, &config, NULL, 0); + ASSERT3U(error, !=, EAGAIN); + + if (config != NULL) { + fnvlist_merge(outnvl, config); + nvlist_free(config); + if (error) + ret = SET_ERROR(EAGAIN); + } else { + ret = error; + } + + return (ret); + } + + static nvlist_t * + objset_stats2nv(dmu_objset_stats_t *stat) + { + nvlist_t *statlist = fnvlist_alloc(); + + fnvlist_add_uint64(statlist, "dds_num_clones", stat->dds_num_clones); + fnvlist_add_uint64(statlist, "dds_creation_txg", + stat->dds_creation_txg); + fnvlist_add_uint64(statlist, "dds_guid", stat->dds_guid); + fnvlist_add_uint8(statlist, "dds_type", (uint8_t)stat->dds_type); + fnvlist_add_uint8(statlist, "dds_is_snapshot", stat->dds_is_snapshot); + fnvlist_add_uint8(statlist, "dds_inconsistent", + stat->dds_inconsistent); + fnvlist_add_string(statlist, "dds_origin", stat->dds_origin); + + return (statlist); + } + + /* Given an objset, retrieve stats and props by adding them to the output nvl */ + static int + objset_render(objset_t *os, nvlist_t *outnvl) + { + int error = 0; + nvlist_t *props = NULL, *statlist = NULL; + dmu_objset_stats_t stats; + + dmu_objset_fast_stat(os, &stats); + + if ((error = dsl_prop_get_all(os, &props)) == 0) { + dmu_objset_stats(os, props); + /* + * NB: zvol_get_stats() will read the objset contents, + * which we aren't supposed to do with a + * DS_MODE_USER hold, because it could be + * inconsistent. So this is a bit of a workaround... + * XXX reading with out owning + */ + if (!stats.dds_inconsistent && + dmu_objset_type(os) == DMU_OST_ZVOL) { + error = zvol_get_stats(os, props); + if (error == EIO) + goto out; + VERIFY0(error); + } + fnvlist_add_nvlist(outnvl, "props", props); + statlist = objset_stats2nv(&stats); + fnvlist_add_nvlist(outnvl, "stats", statlist); + nvlist_free(statlist); + } + + out: + nvlist_free(props); + return (error); + } + + /* + * Note: this IOC can be called internally by other IOCs as an existence + * check against race conditions. Given a dataset name, return its stats + * and props. Optionally we can verify type, which simplifies things for + * callers that may not want to parse stats for themselves (and may discard + * the outnvl in handlers). + */ + static int + zfs_ioc_objset_stats_nvl(const char *data, nvlist_t *innvl, nvlist_t *outnvl) + { + objset_t *os; + int error; + dmu_objset_type_t checktype = DMU_OST_ANY; + boolean_t gettype = B_FALSE; + + if (innvl != NULL) { + if (nvlist_lookup_uint8(innvl, "type", (uint8_t *)&checktype) + == 0) + gettype = B_TRUE; + } + if ((error = dmu_objset_hold(data, FTAG, &os)) == 0) { + error = objset_render(os, outnvl); + dmu_objset_rele(os, FTAG); + + if (error == 0) { + nvlist_t *statlist; + dmu_objset_type_t type; + statlist = fnvlist_lookup_nvlist(outnvl, "stats"); + type = fnvlist_lookup_uint8_t(statlist, "dds_type"); + if (checktype != DMU_OST_ANY && type != checktype) { + error = EEXIST; + fnvlist_remove(outnvl, "stats"); + fnvlist_remove(outnvl, "props"); + } + if (gettype) + fnvlist_add_uint8(outnvl, "type", type); + } + } + + return (error); + } + + /* + * Given a dataset name and an innvl containing a DMU cursor offset, find the + * next child dataset, and return its name, stats, and props and an updated + * cursor. + */ + static int + zfs_ioc_dataset_list_next_nvl(const char *data, nvlist_t *innvl, + nvlist_t *outnvl) + { + objset_t *os; + int error; + uint64_t off; + char *p, *nextds; + char name[MAXNAMELEN]; + size_t len; + size_t orig_len = strlen(data); + + if (innvl == NULL || + nvlist_lookup_uint64(innvl, "offset", &off) != 0) + return (SET_ERROR(EINVAL)); + + (void) strlcpy(name, data, sizeof (name)); + top: + if (error = dmu_objset_hold(name, FTAG, &os)) { + if (error == ENOENT) + error = SET_ERROR(ESRCH); + return (error); + } + + p = strrchr(name, '/'); + if (p == NULL || p[1] != '\0') { + if ((len = strlcat(name, "/", sizeof (name))) >= MAXNAMELEN) { + dmu_objset_rele(os, FTAG); + return (SET_ERROR(ESRCH)); + } + } else { + len = orig_len; + } + p = name + len; + + do { + error = dmu_dir_list_next(os, sizeof (name) - len, p, NULL, + &off); + if (error == ENOENT) + error = ESRCH; + } while (error == 0 && dataset_name_hidden(name)); + dmu_objset_rele(os, FTAG); + + /* + * If it's an internal dataset (ie. with a '$' in its name), + * don't try to get stats for it, otherwise we'll return ENOENT. + */ + if (error == 0 && strchr(name, '$') == NULL) { + error = zfs_ioc_objset_stats_nvl(name, NULL, outnvl); + if (error == ENOENT) { + /* We lost a race with destroy, get the next one. */ + name[orig_len] = '\0'; + goto top; + } + len = strlen(name) + 1; + nextds = kmem_alloc(len, KM_SLEEP); + (void) strlcpy(nextds, name, len); + fnvlist_add_string(outnvl, "nextds", (const char *)nextds); + fnvlist_add_uint64(outnvl, "offset", off); + } + + return (error); + } + + /* + * Given a dataset name and a DMU cursor offset, find its next snapshot, and + * return its name, props, and stats and an updated cursor offset. + */ + static int + zfs_ioc_snapshot_list_next_nvl(const char *data, nvlist_t *innvl, + nvlist_t *outnvl) + { + objset_t *os; + int error; + uint64_t off, obj; + char name[MAXNAMELEN], *nextsnap; + size_t len; + + if (innvl == NULL || + nvlist_lookup_uint64(innvl, "offset", &off) != 0) + return (SET_ERROR(EINVAL)); + + error = dmu_objset_hold(data, FTAG, &os); + if (error != 0) { + return (error == ENOENT ? ESRCH : error); + } + + /* + * A dataset name of maximum length cannot have any snapshots, + * so exit immediately. + */ + (void) strlcpy(name, data, sizeof (name)); + if ((len = strlcat(name, "@", sizeof (name))) >= MAXNAMELEN) { + dmu_objset_rele(os, FTAG); + return (SET_ERROR(ESRCH)); + } + + /* Rest of name buffer is passed so snap ID can be appended. */ + error = dmu_snapshot_list_next(os, sizeof (name) - len, name + len, + &obj, &off, NULL); + + if (error == 0) { + dsl_dataset_t *ds; + dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool; + + error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds); + if (error == 0) { + objset_t *ossnap; + + error = dmu_objset_from_ds(ds, &ossnap); + if (error == 0) + error = objset_render(ossnap, outnvl); + dsl_dataset_rele(ds, FTAG); + } + } else if (error == ENOENT) { + error = ESRCH; + } + + dmu_objset_rele(os, FTAG); + + if (error == 0) { + len = strlen(name) + 1; + nextsnap = kmem_alloc(len, KM_SLEEP); + (void) strlcpy(nextsnap, name, len); + fnvlist_add_string(outnvl, "nextsnap", (const char *)nextsnap); + fnvlist_add_uint64(outnvl, "offset", off); + } + return (error); + } + + static int + zfs_ioc_pool_get_props_nvl(const char *poolname, nvlist_t *innvl, + nvlist_t *outnvl) + { + spa_t *spa; + int error; + nvlist_t *props = NULL; + + ASSERT3P(innvl, ==, NULL); + if ((error = spa_open(poolname, &spa, FTAG)) != 0) { + /* + * If the pool is faulted, there may be properties we can still + * get (such as altroot and cachefile), so attempt to get them + * anyway. + */ + mutex_enter(&spa_namespace_lock); + if ((spa = spa_lookup(poolname)) != NULL) + error = spa_prop_get(spa, &props); + mutex_exit(&spa_namespace_lock); + } else { + error = spa_prop_get(spa, &props); + spa_close(spa, FTAG); + } + + if (props != NULL) { + fnvlist_merge(outnvl, props); + nvlist_free(props); + } else { + ASSERT3S(error, !=, 0); + } + + return (error); + } + + /* ARGSUSED */ + static int + zfs_ioc_check_krrp(const char *dataset, nvlist_t *innvl, nvlist_t *outnvl) + { + spa_t *spa; + int err; + + /* + * Here we use different way to open spa for the given pool, + * because the pool maybe faulted + */ + + mutex_enter(&spa_namespace_lock); + if ((spa = spa_lookup(dataset)) == NULL) { + mutex_exit(&spa_namespace_lock); + /* From KRRP side everything nice */ + return (0); + } + + spa_open_ref(spa, FTAG); + mutex_exit(&spa_namespace_lock); + + err = autosnap_check_for_destroy(spa_get_autosnap(spa), dataset); + if (err == 0) + err = ENOTSUP; + + mutex_enter(&spa_namespace_lock); + spa_close(spa, FTAG); + mutex_exit(&spa_namespace_lock); + + return (err != 0 ? SET_ERROR(err) : 0); + } + static void zfs_ioctl_init(void) { + zfs_ioctl_register("bulk_list", ZFS_IOC_BULK_LIST, + zfs_ioc_list_from_cursor, zfs_secpolicy_read, + DATASET_NAME, POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); + zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT, zfs_ioc_snapshot, zfs_secpolicy_snapshot, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); zfs_ioctl_register("log_history", ZFS_IOC_LOG_HISTORY,
*** 5794,5811 **** zfs_ioctl_register("clone", ZFS_IOC_CLONE, zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); - zfs_ioctl_register("remap", ZFS_IOC_REMAP, - zfs_ioc_remap, zfs_secpolicy_remap, DATASET_NAME, - POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE); - zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS, zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); zfs_ioctl_register("hold", ZFS_IOC_HOLD, zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); zfs_ioctl_register("release", ZFS_IOC_RELEASE, zfs_ioc_release, zfs_secpolicy_release, POOL_NAME, --- 7215,7258 ---- zfs_ioctl_register("clone", ZFS_IOC_CLONE, zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS, zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); + zfs_ioctl_register("check_krrp", ZFS_IOC_CHECK_KRRP, + zfs_ioc_check_krrp, zfs_secpolicy_read, DATASET_NAME, + POOL_CHECK_NONE, B_FALSE, B_FALSE); + + zfs_ioctl_register("pool_stats_nvl", ZFS_IOC_POOL_STATS_NVL, + zfs_ioc_pool_stats_nvl, zfs_secpolicy_read, POOL_NAME, + POOL_CHECK_NONE, B_FALSE, B_FALSE); + + zfs_ioctl_register("pool_configs_nvl", ZFS_IOC_POOL_CONFIGS_NVL, + zfs_ioc_pool_configs_nvl, zfs_secpolicy_none, NO_NAME, + POOL_CHECK_NONE, B_FALSE, B_FALSE); + + zfs_ioctl_register("pool_get_props_nvl", ZFS_IOC_POOL_GET_PROPS_NVL, + zfs_ioc_pool_get_props_nvl, zfs_secpolicy_read, POOL_NAME, + POOL_CHECK_NONE, B_FALSE, B_FALSE); + + zfs_ioctl_register("objset_stats_nvl", ZFS_IOC_OBJSET_STATS_NVL, + zfs_ioc_objset_stats_nvl, zfs_secpolicy_read, DATASET_NAME, + POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); + + zfs_ioctl_register("dataset_list_next_nvl", + ZFS_IOC_DATASET_LIST_NEXT_NVL, zfs_ioc_dataset_list_next_nvl, + zfs_secpolicy_read, DATASET_NAME, POOL_CHECK_SUSPENDED, B_FALSE, + B_FALSE); + + zfs_ioctl_register("snapshot_list_next_nvl", + ZFS_IOC_SNAPSHOT_LIST_NEXT_NVL, zfs_ioc_snapshot_list_next_nvl, + zfs_secpolicy_read, DATASET_NAME, POOL_CHECK_SUSPENDED, B_FALSE, + B_FALSE); + zfs_ioctl_register("hold", ZFS_IOC_HOLD, zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); zfs_ioctl_register("release", ZFS_IOC_RELEASE, zfs_ioc_release, zfs_secpolicy_release, POOL_NAME,
*** 5835,5853 **** --- 7282,7307 ---- zfs_ioctl_register("channel_program", ZFS_IOC_CHANNEL_PROGRAM, zfs_ioc_channel_program, zfs_secpolicy_config, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); + zfs_ioctl_register("set_props_mds", ZFS_IOC_SET_PROPS_MDS, + zfs_ioc_set_prop_mds, zfs_secpolicy_config, + POOL_NAME, + POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); + /* IOCTLS that use the legacy function signature */ zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_READONLY); zfs_ioctl_register_pool(ZFS_IOC_POOL_CREATE, zfs_ioc_pool_create, zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SCAN, zfs_ioc_pool_scan); + zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_TRIM, + zfs_ioc_pool_trim); zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_UPGRADE, zfs_ioc_pool_upgrade); zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ADD, zfs_ioc_vdev_add); zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_REMOVE,
*** 5856,5865 **** --- 7310,7321 ---- zfs_ioc_vdev_set_state); zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ATTACH, zfs_ioc_vdev_attach); zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_DETACH, zfs_ioc_vdev_detach); + zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETL2ADDDT, + zfs_ioc_vdev_setl2adddt); zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETPATH, zfs_ioc_vdev_setpath); zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETFRU, zfs_ioc_vdev_setfru); zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SET_PROPS,
*** 5906,5919 **** zfs_ioctl_register_pool(ZFS_IOC_POOL_IMPORT, zfs_ioc_pool_import, zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_READONLY); zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen, zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN, zfs_ioc_space_written); zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_RECVD_PROPS, zfs_ioc_objset_recvd_props); zfs_ioctl_register_dataset_read(ZFS_IOC_NEXT_OBJ, --- 7362,7388 ---- zfs_ioctl_register_pool(ZFS_IOC_POOL_IMPORT, zfs_ioc_pool_import, zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE); zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen, zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_VDEV_SET_PROPS, zfs_ioc_vdev_set_props, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_VDEV_GET_PROPS, zfs_ioc_vdev_get_props, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_COS_ALLOC, zfs_ioc_cos_alloc, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_COS_FREE, zfs_ioc_cos_free, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_COS_LIST, zfs_ioc_cos_list, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_COS_SET_PROPS, zfs_ioc_cos_set_props, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); ! zfs_ioctl_register_pool(ZFS_IOC_COS_GET_PROPS, zfs_ioc_cos_get_props, ! zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN, zfs_ioc_space_written); zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_RECVD_PROPS, zfs_ioc_objset_recvd_props); zfs_ioctl_register_dataset_read(ZFS_IOC_NEXT_OBJ,
*** 6401,6410 **** --- 7870,7883 ---- error = ldi_ident_from_mod(&modlinkage, &zfs_li); ASSERT(error == 0); mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); + if (sysevent_evc_bind(ZFS_EVENT_CHANNEL, &zfs_channel, + EVCH_HOLD_PEND | EVCH_CREAT) != 0) + cmn_err(CE_NOTE, "Failed to bind to zfs event channel"); + return (0); } int _fini(void)
*** 6430,6439 **** --- 7903,7915 ---- tsd_destroy(&zfs_fsyncer_key); ldi_ident_release(zfs_li); zfs_li = NULL; mutex_destroy(&zfs_share_lock); + if (zfs_channel) + (void) sysevent_evc_unbind(zfs_channel); + return (error); } int _info(struct modinfo *modinfop)