Date: Wed, 13 Sep 2017 10:45:49 +0000 (UTC) From: Andriy Gapon <avg@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r323530 - vendor-sys/illumos/dist/common/zfs vendor-sys/illumos/dist/uts/common vendor-sys/illumos/dist/uts/common/fs/zfs vendor-sys/illumos/dist/uts/common/fs/zfs/lua vendor-sys/illumo... Message-ID: <201709131045.v8DAjntu063845@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: avg Date: Wed Sep 13 10:45:49 2017 New Revision: 323530 URL: https://svnweb.freebsd.org/changeset/base/323530 Log: 7431 ZFS Channel Programs illumos/illumos-gate@dfc115332c94a2f62058ac7f2bce7631fbd20b3d https://github.com/illumos/illumos-gate/commit/dfc115332c94a2f62058ac7f2bce7631fbd20b3d https://www.illumos.org/issues/7431 ZFS channel programs (ZCP) adds support for performing compound ZFS administrative actions via Lua scripts in a sandboxed environment (with time and memory limits). This initial commit includes both base support for running ZCP scripts, and a small initial library of API calls which support getting properties and listing, destroying, and promoting datasets. Testing: in addition to the included unit tests, channel programs have been in use at Delphix for several months for batch destroying filesystems. The dsl_destroy_snaps_nvl() call has also been replaced with For reference, the new zfs-program manpage is included below. ZFS-PROGRAM(1M) 1M ZFS-PROGRAM(1M) NAME zfs program – executes ZFS channel programs SYNOPSIS zfs program [-t timeout] [-m memory-limit] pool script DESCRIPTION The ZFS channel program interface allows ZFS administrative operations to be run programmatically as a Lua script. The entire script is executed atomically, with no other administrative operations taking effect concurrently. A library of ZFS calls is made available to channel program scripts. Channel programs may only be run with root privileges. A modified version of the Lua 5.2 interpreter is used to run channel program scripts. The Lua 5.2 manual can be found at: http://www.lua.org/manual/5.2/ ... Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: John Kennedy <john.kennedy@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Approved by: Garrett D'Amore <garrett@damore.org> Author: Chris Williamson <chris.williamson@delphix.com> Added: vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ vendor-sys/illumos/dist/uts/common/fs/zfs/lua/README.zfs vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lapi.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lapi.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lauxlib.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lauxlib.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lbaselib.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lbitlib.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcode.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcode.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcompat.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcorolib.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lctype.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lctype.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldebug.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldebug.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldo.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldo.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldump.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lfunc.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lfunc.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lgc.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lgc.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/llex.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/llex.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/llimits.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lmem.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lmem.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lobject.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lobject.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lopcodes.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lopcodes.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lparser.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lparser.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstate.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstate.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstring.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstring.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstrlib.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltable.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltable.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltablib.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltm.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltm.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lua.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/luaconf.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lualib.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lundump.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lundump.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lvm.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lvm.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lzio.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lzio.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp_global.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp_iter.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp_prop.h (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/zcp.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_get.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_global.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_iter.c (contents, props changed) vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_synctask.c (contents, props changed) Modified: vendor-sys/illumos/dist/common/zfs/zfs_prop.c vendor-sys/illumos/dist/uts/common/Makefile.files vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dir.c vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_dataset.h vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_destroy.h vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_dir.h vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zfs_ioctl.h vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zfs_vfsops.h vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_ioctl.c vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vfsops.c vendor-sys/illumos/dist/uts/common/sys/fs/zfs.h Changes in other areas also in this revision: Added: vendor/illumos/dist/man/man1m/zfs-program.1m Modified: vendor/illumos/dist/cmd/zfs/zfs_main.c vendor/illumos/dist/cmd/zpool/zpool_main.c vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c vendor/illumos/dist/lib/libzfs/common/libzfs_impl.h vendor/illumos/dist/lib/libzfs/common/libzfs_util.c vendor/illumos/dist/lib/libzfs_core/common/libzfs_core.c vendor/illumos/dist/lib/libzfs_core/common/libzfs_core.h vendor/illumos/dist/lib/libzpool/common/kernel.c vendor/illumos/dist/lib/libzpool/common/sys/zfs_context.h vendor/illumos/dist/man/man1m/zfs.1m Modified: vendor-sys/illumos/dist/common/zfs/zfs_prop.c ============================================================================== --- vendor-sys/illumos/dist/common/zfs/zfs_prop.c Wed Sep 13 10:41:47 2017 (r323529) +++ vendor-sys/illumos/dist/common/zfs/zfs_prop.c Wed Sep 13 10:45:49 2017 (r323530) @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2014 by Delphix. All rights reserved. + * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2014 Integros [integros.com] @@ -381,7 +381,8 @@ zfs_prop_init(void) zprop_register_number(ZFS_PROP_WRITTEN, "written", 0, PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "WRITTEN"); zprop_register_number(ZFS_PROP_LOGICALUSED, "logicalused", 0, - PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LUSED"); + PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", + "LUSED"); zprop_register_number(ZFS_PROP_LOGICALREFERENCED, "logicalreferenced", 0, PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LREFER"); @@ -582,6 +583,15 @@ zfs_prop_readonly(zfs_prop_t prop) { return (zfs_prop_table[prop].pd_attr == PROP_READONLY || zfs_prop_table[prop].pd_attr == PROP_ONETIME); +} + +/* + * Returns TRUE if the property is visible (not hidden). + */ +boolean_t +zfs_prop_visible(zfs_prop_t prop) +{ + return (zfs_prop_table[prop].pd_visible); } /* Modified: vendor-sys/illumos/dist/uts/common/Makefile.files ============================================================================== --- vendor-sys/illumos/dist/uts/common/Makefile.files Wed Sep 13 10:41:47 2017 (r323529) +++ vendor-sys/illumos/dist/uts/common/Makefile.files Wed Sep 13 10:45:49 2017 (r323530) @@ -1308,6 +1308,35 @@ SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node. $(SMBFS_COMMON_OBJS) +LUA_OBJS += \ + ldo.o \ + lvm.o \ + lbitlib.o \ + lopcodes.o \ + lstring.o \ + ltable.o \ + ltm.o \ + lcorolib.o \ + lauxlib.o \ + ldebug.o \ + lstate.o \ + lgc.o \ + lmem.o \ + lctype.o \ + lfunc.o \ + ldump.o \ + lundump.o \ + lstrlib.o \ + ltablib.o \ + lapi.o \ + lobject.o \ + lbaselib.o \ + lcompat.o \ + lzio.o \ + lcode.o \ + llex.o \ + lparser.o + ZFS_COMMON_OBJS += \ abd.o \ arc.o \ @@ -1375,6 +1404,11 @@ ZFS_COMMON_OBJS += \ zap.o \ zap_leaf.o \ zap_micro.o \ + zcp.o \ + zcp_get.o \ + zcp_global.o \ + zcp_iter.o \ + zcp_synctask.o \ zfs_byteswap.o \ zfs_debug.o \ zfs_fm.o \ @@ -1958,7 +1992,7 @@ IXGBE_OBJS = ixgbe_82598.o ixgbe_82599.o ixgbe_api. # illumos-written ones. I40E_OBJS = i40e_main.o i40e_osdep.o i40e_intr.o i40e_transceiver.o \ - i40e_stats.o i40e_gld.o + i40e_stats.o i40e_gld.o # Intel-written ones. I40E_INTC_OBJS = i40e_adminq.o i40e_common.o i40e_hmc.o i40e_lan_hmc.o \ i40e_nvm.o Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c ============================================================================== --- vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c Wed Sep 13 10:41:47 2017 (r323529) +++ vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c Wed Sep 13 10:45:49 2017 (r323530) @@ -1616,7 +1616,6 @@ dsl_dataset_snapshot_tmp(const char *fsname, const cha return (error); } - void dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) { @@ -1684,30 +1683,17 @@ dsl_dataset_sync_done(dsl_dataset_t *ds, dmu_tx_t *tx) dmu_buf_rele(ds->ds_dbuf, ds); } -static void -get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) +int +get_clones_stat_impl(dsl_dataset_t *ds, nvlist_t *val) { uint64_t count = 0; objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; zap_cursor_t zc; zap_attribute_t za; - nvlist_t *propval = fnvlist_alloc(); - nvlist_t *val; ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool)); /* - * We use nvlist_alloc() instead of fnvlist_alloc() because the - * latter would allocate the list with NV_UNIQUE_NAME flag. - * As a result, every time a clone name is appended to the list - * it would be (linearly) searched for for a duplicate name. - * We already know that all clone names must be unique and we - * want avoid the quadratic complexity of double-checking that - * because we can have a large number of clones. - */ - VERIFY0(nvlist_alloc(&val, 0, KM_SLEEP)); - - /* * There may be missing entries in ds_next_clones_obj * due to a bug in a previous version of the code. * Only trust it if it has the right number of entries. @@ -1716,8 +1702,9 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) VERIFY0(zap_count(mos, dsl_dataset_phys(ds)->ds_next_clones_obj, &count)); } - if (count != dsl_dataset_phys(ds)->ds_num_children - 1) - goto fail; + if (count != dsl_dataset_phys(ds)->ds_num_children - 1) { + return (ENOENT); + } for (zap_cursor_init(&zc, mos, dsl_dataset_phys(ds)->ds_next_clones_obj); zap_cursor_retrieve(&zc, &za) == 0; @@ -1731,16 +1718,43 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) dsl_dataset_rele(clone, FTAG); } zap_cursor_fini(&zc); - fnvlist_add_nvlist(propval, ZPROP_VALUE, val); - fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), propval); -fail: - nvlist_free(val); - nvlist_free(propval); + return (0); } -static void -get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv) +void +get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) { + nvlist_t *propval = fnvlist_alloc(); + nvlist_t *val; + + /* + * We use nvlist_alloc() instead of fnvlist_alloc() because the + * latter would allocate the list with NV_UNIQUE_NAME flag. + * As a result, every time a clone name is appended to the list + * it would be (linearly) searched for for a duplicate name. + * We already know that all clone names must be unique and we + * want avoid the quadratic complexity of double-checking that + * because we can have a large number of clones. + */ + VERIFY0(nvlist_alloc(&val, 0, KM_SLEEP)); + + if (get_clones_stat_impl(ds, val) == 0) { + fnvlist_add_nvlist(propval, ZPROP_VALUE, val); + fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), + propval); + } else { + nvlist_free(val); + nvlist_free(propval); + } +} + +/* + * Returns a string that represents the receive resume stats token. It should + * be freed with strfree(). + */ +char * +get_receive_resume_stats_impl(dsl_dataset_t *ds) +{ dsl_pool_t *dp = ds->ds_dir->dd_pool; if (dsl_dataset_has_resume_receive_state(ds)) { @@ -1807,84 +1821,359 @@ get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t * ZFS_SEND_RESUME_TOKEN_VERSION, (longlong_t)cksum.zc_word[0], (longlong_t)packed_size, str); - dsl_prop_nvlist_add_string(nv, - ZFS_PROP_RECEIVE_RESUME_TOKEN, propval); kmem_free(packed, packed_size); kmem_free(str, compressed_size * 2 + 1); kmem_free(compressed, packed_size); - strfree(propval); + return (propval); } + return (strdup("")); } +/* + * Returns a string that represents the receive resume stats token of the + * dataset's child. It should be freed with strfree(). + */ +char * +get_child_receive_stats(dsl_dataset_t *ds) +{ + char recvname[ZFS_MAX_DATASET_NAME_LEN + 6]; + dsl_dataset_t *recv_ds; + dsl_dataset_name(ds, recvname); + if (strlcat(recvname, "/", sizeof (recvname)) < + sizeof (recvname) && + strlcat(recvname, recv_clone_name, sizeof (recvname)) < + sizeof (recvname) && + dsl_dataset_hold(ds->ds_dir->dd_pool, recvname, FTAG, + &recv_ds) == 0) { + char *propval = get_receive_resume_stats_impl(recv_ds); + dsl_dataset_rele(recv_ds, FTAG); + return (propval); + } + return (strdup("")); +} + +static void +get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv) +{ + char *propval = get_receive_resume_stats_impl(ds); + if (strcmp(propval, "") != 0) { + dsl_prop_nvlist_add_string(nv, + ZFS_PROP_RECEIVE_RESUME_TOKEN, propval); + } else { + char *childval = get_child_receive_stats(ds); + if (strcmp(childval, "") != 0) { + dsl_prop_nvlist_add_string(nv, + ZFS_PROP_RECEIVE_RESUME_TOKEN, childval); + } + strfree(childval); + } + strfree(propval); +} + +uint64_t +dsl_get_refratio(dsl_dataset_t *ds) +{ + uint64_t ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 : + (dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 / + dsl_dataset_phys(ds)->ds_compressed_bytes); + return (ratio); +} + +uint64_t +dsl_get_logicalreferenced(dsl_dataset_t *ds) +{ + return (dsl_dataset_phys(ds)->ds_uncompressed_bytes); +} + +uint64_t +dsl_get_compressratio(dsl_dataset_t *ds) +{ + if (ds->ds_is_snapshot) { + return (dsl_get_refratio(ds)); + } else { + dsl_dir_t *dd = ds->ds_dir; + mutex_enter(&dd->dd_lock); + uint64_t val = dsl_dir_get_compressratio(dd); + mutex_exit(&dd->dd_lock); + return (val); + } +} + +uint64_t +dsl_get_used(dsl_dataset_t *ds) +{ + if (ds->ds_is_snapshot) { + return (dsl_dataset_phys(ds)->ds_unique_bytes); + } else { + dsl_dir_t *dd = ds->ds_dir; + mutex_enter(&dd->dd_lock); + uint64_t val = dsl_dir_get_used(dd); + mutex_exit(&dd->dd_lock); + return (val); + } +} + +uint64_t +dsl_get_creation(dsl_dataset_t *ds) +{ + return (dsl_dataset_phys(ds)->ds_creation_time); +} + +uint64_t +dsl_get_creationtxg(dsl_dataset_t *ds) +{ + return (dsl_dataset_phys(ds)->ds_creation_txg); +} + +uint64_t +dsl_get_refquota(dsl_dataset_t *ds) +{ + return (ds->ds_quota); +} + +uint64_t +dsl_get_refreservation(dsl_dataset_t *ds) +{ + return (ds->ds_reserved); +} + +uint64_t +dsl_get_guid(dsl_dataset_t *ds) +{ + return (dsl_dataset_phys(ds)->ds_guid); +} + +uint64_t +dsl_get_unique(dsl_dataset_t *ds) +{ + return (dsl_dataset_phys(ds)->ds_unique_bytes); +} + +uint64_t +dsl_get_objsetid(dsl_dataset_t *ds) +{ + return (ds->ds_object); +} + +uint64_t +dsl_get_userrefs(dsl_dataset_t *ds) +{ + return (ds->ds_userrefs); +} + +uint64_t +dsl_get_defer_destroy(dsl_dataset_t *ds) +{ + return (DS_IS_DEFER_DESTROY(ds) ? 1 : 0); +} + +uint64_t +dsl_get_referenced(dsl_dataset_t *ds) +{ + return (dsl_dataset_phys(ds)->ds_referenced_bytes); +} + +uint64_t +dsl_get_numclones(dsl_dataset_t *ds) +{ + ASSERT(ds->ds_is_snapshot); + return (dsl_dataset_phys(ds)->ds_num_children - 1); +} + +uint64_t +dsl_get_inconsistent(dsl_dataset_t *ds) +{ + return ((dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT) ? + 1 : 0); +} + +uint64_t +dsl_get_available(dsl_dataset_t *ds) +{ + uint64_t refdbytes = dsl_get_referenced(ds); + uint64_t availbytes = dsl_dir_space_available(ds->ds_dir, + NULL, 0, TRUE); + if (ds->ds_reserved > dsl_dataset_phys(ds)->ds_unique_bytes) { + availbytes += + ds->ds_reserved - dsl_dataset_phys(ds)->ds_unique_bytes; + } + if (ds->ds_quota != 0) { + /* + * Adjust available bytes according to refquota + */ + if (refdbytes < ds->ds_quota) { + availbytes = MIN(availbytes, + ds->ds_quota - refdbytes); + } else { + availbytes = 0; + } + } + return (availbytes); +} + +int +dsl_get_written(dsl_dataset_t *ds, uint64_t *written) +{ + dsl_pool_t *dp = ds->ds_dir->dd_pool; + dsl_dataset_t *prev; + int err = dsl_dataset_hold_obj(dp, + dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev); + if (err == 0) { + uint64_t comp, uncomp; + err = dsl_dataset_space_written(prev, ds, written, + &comp, &uncomp); + dsl_dataset_rele(prev, FTAG); + } + return (err); +} + +/* + * 'snap' should be a buffer of size ZFS_MAX_DATASET_NAME_LEN. + */ +int +dsl_get_prev_snap(dsl_dataset_t *ds, char *snap) +{ + dsl_pool_t *dp = ds->ds_dir->dd_pool; + if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) { + dsl_dataset_name(ds->ds_prev, snap); + return (0); + } else { + return (ENOENT); + } +} + +/* + * Returns the mountpoint property and source for the given dataset in the value + * and source buffers. The value buffer must be at least as large as MAXPATHLEN + * and the source buffer as least as large a ZFS_MAX_DATASET_NAME_LEN. + * Returns 0 on success and an error on failure. + */ +int +dsl_get_mountpoint(dsl_dataset_t *ds, const char *dsname, char *value, + char *source) +{ + int error; + dsl_pool_t *dp = ds->ds_dir->dd_pool; + + /* Retrieve the mountpoint value stored in the zap opbject */ + error = dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1, + ZAP_MAXVALUELEN, value, source); + if (error != 0) { + return (error); + } + + /* Process the dsname and source to find the full mountpoint string */ + if (value[0] == '/') { + char *buf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); + char *root = buf; + const char *relpath; + + /* + * If we inherit the mountpoint, even from a dataset + * with a received value, the source will be the path of + * the dataset we inherit from. If source is + * ZPROP_SOURCE_VAL_RECVD, the received value is not + * inherited. + */ + if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) { + relpath = ""; + } else { + ASSERT0(strncmp(dsname, source, strlen(source))); + relpath = dsname + strlen(source); + if (relpath[0] == '/') + relpath++; + } + + spa_altroot(dp->dp_spa, root, ZAP_MAXVALUELEN); + + /* + * Special case an alternate root of '/'. This will + * avoid having multiple leading slashes in the + * mountpoint path. + */ + if (strcmp(root, "/") == 0) + root++; + + /* + * If the mountpoint is '/' then skip over this + * if we are obtaining either an alternate root or + * an inherited mountpoint. + */ + char *mnt = value; + if (value[1] == '\0' && (root[0] != '\0' || + relpath[0] != '\0')) + mnt = value + 1; + + if (relpath[0] == '\0') { + (void) snprintf(value, ZAP_MAXVALUELEN, "%s%s", + root, mnt); + } else { + (void) snprintf(value, ZAP_MAXVALUELEN, "%s%s%s%s", + root, mnt, relpath[0] == '@' ? "" : "/", + relpath); + } + kmem_free(buf, ZAP_MAXVALUELEN); + } else { + /* 'legacy' or 'none' */ + (void) snprintf(value, ZAP_MAXVALUELEN, "%s", value); + } + return (0); +} + void dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) { dsl_pool_t *dp = ds->ds_dir->dd_pool; - uint64_t refd, avail, uobjs, aobjs, ratio; ASSERT(dsl_pool_config_held(dp)); - ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 : - (dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 / - dsl_dataset_phys(ds)->ds_compressed_bytes); - - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, + dsl_get_refratio(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALREFERENCED, - dsl_dataset_phys(ds)->ds_uncompressed_bytes); + dsl_get_logicalreferenced(ds)); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, + dsl_get_compressratio(ds)); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, + dsl_get_used(ds)); if (ds->ds_is_snapshot) { - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio); - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, - dsl_dataset_phys(ds)->ds_unique_bytes); get_clones_stat(ds, nv); } else { - if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) { - char buf[ZFS_MAX_DATASET_NAME_LEN]; - dsl_dataset_name(ds->ds_prev, buf); - dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, buf); - } - + char buf[ZFS_MAX_DATASET_NAME_LEN]; + if (dsl_get_prev_snap(ds, buf) == 0) + dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, + buf); dsl_dir_stats(ds->ds_dir, nv); } - dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); - + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, + dsl_get_available(ds)); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, + dsl_get_referenced(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, - dsl_dataset_phys(ds)->ds_creation_time); + dsl_get_creation(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, - dsl_dataset_phys(ds)->ds_creation_txg); + dsl_get_creationtxg(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, - ds->ds_quota); + dsl_get_refquota(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, - ds->ds_reserved); + dsl_get_refreservation(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, - dsl_dataset_phys(ds)->ds_guid); + dsl_get_guid(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE, - dsl_dataset_phys(ds)->ds_unique_bytes); + dsl_get_unique(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, - ds->ds_object); + dsl_get_objsetid(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, - ds->ds_userrefs); + dsl_get_userrefs(ds)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, - DS_IS_DEFER_DESTROY(ds) ? 1 : 0); + dsl_get_defer_destroy(ds)); if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { - uint64_t written, comp, uncomp; - dsl_pool_t *dp = ds->ds_dir->dd_pool; - dsl_dataset_t *prev; - - int err = dsl_dataset_hold_obj(dp, - dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev); - if (err == 0) { - err = dsl_dataset_space_written(prev, ds, &written, - &comp, &uncomp); - dsl_dataset_rele(prev, FTAG); - if (err == 0) { - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN, - written); - } + uint64_t written; + if (dsl_get_written(ds, &written) == 0) { + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN, + written); } } @@ -1921,27 +2210,19 @@ dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_st dsl_pool_t *dp = ds->ds_dir->dd_pool; ASSERT(dsl_pool_config_held(dp)); - stat->dds_creation_txg = dsl_dataset_phys(ds)->ds_creation_txg; - stat->dds_inconsistent = - dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT; - stat->dds_guid = dsl_dataset_phys(ds)->ds_guid; + stat->dds_creation_txg = dsl_get_creationtxg(ds); + stat->dds_inconsistent = dsl_get_inconsistent(ds); + stat->dds_guid = dsl_get_guid(ds); stat->dds_origin[0] = '\0'; if (ds->ds_is_snapshot) { stat->dds_is_snapshot = B_TRUE; - stat->dds_num_clones = - dsl_dataset_phys(ds)->ds_num_children - 1; + stat->dds_num_clones = dsl_get_numclones(ds); } else { stat->dds_is_snapshot = B_FALSE; stat->dds_num_clones = 0; if (dsl_dir_is_clone(ds->ds_dir)) { - dsl_dataset_t *ods; - - VERIFY0(dsl_dataset_hold_obj(dp, - dsl_dir_phys(ds->ds_dir)->dd_origin_obj, - FTAG, &ods)); - dsl_dataset_name(ods, stat->dds_origin); - dsl_dataset_rele(ods, FTAG); + dsl_dir_get_origin(ds->ds_dir, stat->dds_origin); } } } @@ -2348,22 +2629,12 @@ struct promotenode { dsl_dataset_t *ds; }; -typedef struct dsl_dataset_promote_arg { - const char *ddpa_clonename; - dsl_dataset_t *ddpa_clone; - list_t shared_snaps, origin_snaps, clone_snaps; - dsl_dataset_t *origin_origin; /* origin of the origin */ - uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; - char *err_ds; - cred_t *cr; -} dsl_dataset_promote_arg_t; - static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); static int promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp, void *tag); static void promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag); -static int +int dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) { dsl_dataset_promote_arg_t *ddpa = arg; @@ -2375,14 +2646,19 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) uint64_t unused; uint64_t ss_mv_cnt; size_t max_snap_len; + boolean_t conflicting_snaps; err = promote_hold(ddpa, dp, FTAG); if (err != 0) return (err); hds = ddpa->ddpa_clone; + snap = list_head(&ddpa->shared_snaps); + origin_ds = snap->ds; max_snap_len = MAXNAMELEN - strlen(ddpa->ddpa_clonename) - 1; + snap = list_head(&ddpa->origin_snaps); + if (dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE) { promote_rele(ddpa, FTAG); return (SET_ERROR(EXDEV)); @@ -2397,9 +2673,6 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) return (0); } - snap = list_head(&ddpa->shared_snaps); - origin_ds = snap->ds; - /* compute origin's new unique space */ snap = list_tail(&ddpa->clone_snaps); ASSERT3U(dsl_dataset_phys(snap->ds)->ds_prev_snap_obj, ==, @@ -2423,6 +2696,7 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) * Note however, if we stop before we reach the ORIGIN we get: * uN + kN + kN-1 + ... + kM - uM-1 */ + conflicting_snaps = B_FALSE; ss_mv_cnt = 0; ddpa->used = dsl_dataset_phys(origin_ds)->ds_referenced_bytes; ddpa->comp = dsl_dataset_phys(origin_ds)->ds_compressed_bytes; @@ -2451,12 +2725,12 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) } err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); if (err == 0) { - (void) strcpy(ddpa->err_ds, snap->ds->ds_snapname); - err = SET_ERROR(EEXIST); + fnvlist_add_boolean(ddpa->err_ds, + snap->ds->ds_snapname); + conflicting_snaps = B_TRUE; + } else if (err != ENOENT) { goto out; } - if (err != ENOENT) - goto out; /* The very first snapshot does not have a deadlist */ if (dsl_dataset_phys(ds)->ds_prev_snap_obj == 0) @@ -2470,6 +2744,15 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) } /* + * In order to return the full list of conflicting snapshots, we check + * whether there was a conflict after traversing all of them. + */ + if (conflicting_snaps) { + err = SET_ERROR(EEXIST); + goto out; + } + + /* * If we are a clone of a clone then we never reached ORIGIN, * so we need to subtract out the clone origin's used space. */ @@ -2531,7 +2814,7 @@ out: return (err); } -static void +void dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx) { dsl_dataset_promote_arg_t *ddpa = arg; @@ -2856,6 +3139,7 @@ dsl_dataset_promote(const char *name, char *conflsnap) dsl_dataset_promote_arg_t ddpa = { 0 }; uint64_t numsnaps; int error; + nvpair_t *snap_pair; objset_t *os; /* @@ -2873,12 +3157,22 @@ dsl_dataset_promote(const char *name, char *conflsnap) return (error); ddpa.ddpa_clonename = name; - ddpa.err_ds = conflsnap; + ddpa.err_ds = fnvlist_alloc(); ddpa.cr = CRED(); - return (dsl_sync_task(name, dsl_dataset_promote_check, + error = dsl_sync_task(name, dsl_dataset_promote_check, dsl_dataset_promote_sync, &ddpa, - 2 + numsnaps, ZFS_SPACE_CHECK_RESERVED)); + 2 + numsnaps, ZFS_SPACE_CHECK_RESERVED); + + /* + * Return the first conflicting snapshot found. + */ + snap_pair = nvlist_next_nvpair(ddpa.err_ds, NULL); + if (snap_pair != NULL && conflsnap != NULL) + (void) strcpy(conflsnap, nvpair_name(snap_pair)); + + fnvlist_free(ddpa.err_ds); + return (error); } int Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c ============================================================================== --- vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c Wed Sep 13 10:41:47 2017 (r323529) +++ vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c Wed Sep 13 10:45:49 2017 (r323530) @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 by Delphix. All rights reserved. + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2013 by Joyent, Inc. All rights reserved. * Copyright (c) 2014 Integros [integros.com] @@ -30,6 +30,7 @@ #include <sys/dsl_userhold.h> #include <sys/dsl_dataset.h> #include <sys/dsl_synctask.h> +#include <sys/dsl_destroy.h> #include <sys/dmu_tx.h> #include <sys/dsl_pool.h> #include <sys/dsl_dir.h> @@ -41,14 +42,8 @@ #include <sys/zfs_ioctl.h> #include <sys/dsl_deleg.h> #include <sys/dmu_impl.h> +#include <sys/zcp.h> -typedef struct dmu_snapshots_destroy_arg { - nvlist_t *dsda_snaps; - nvlist_t *dsda_successful_snaps; - boolean_t dsda_defer; - nvlist_t *dsda_errlist; -} dmu_snapshots_destroy_arg_t; - int dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer) { @@ -85,51 +80,33 @@ dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boo return (0); } -static int +int dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx) { - dmu_snapshots_destroy_arg_t *dsda = arg; + dsl_destroy_snapshot_arg_t *ddsa = arg; + const char *dsname = ddsa->ddsa_name; + boolean_t defer = ddsa->ddsa_defer; + dsl_pool_t *dp = dmu_tx_pool(tx); - nvpair_t *pair; int error = 0; + dsl_dataset_t *ds; - if (!dmu_tx_is_syncing(tx)) + error = dsl_dataset_hold(dp, dsname, FTAG, &ds); + + /* + * If the snapshot does not exist, silently ignore it, and + * dsl_destroy_snapshot_sync() will be a no-op + * (it's "already destroyed"). + */ + if (error == ENOENT) return (0); - for (pair = nvlist_next_nvpair(dsda->dsda_snaps, NULL); - pair != NULL; pair = nvlist_next_nvpair(dsda->dsda_snaps, pair)) { - dsl_dataset_t *ds; - - error = dsl_dataset_hold(dp, nvpair_name(pair), - FTAG, &ds); - - /* - * If the snapshot does not exist, silently ignore it - * (it's "already destroyed"). - */ - if (error == ENOENT) - continue; - - if (error == 0) { - error = dsl_destroy_snapshot_check_impl(ds, - dsda->dsda_defer); - dsl_dataset_rele(ds, FTAG); - } - - if (error == 0) { - fnvlist_add_boolean(dsda->dsda_successful_snaps, - nvpair_name(pair)); - } else { - fnvlist_add_int32(dsda->dsda_errlist, - nvpair_name(pair), error); - } + if (error == 0) { + error = dsl_destroy_snapshot_check_impl(ds, defer); + dsl_dataset_rele(ds, FTAG); } - pair = nvlist_next_nvpair(dsda->dsda_errlist, NULL); - if (pair != NULL) - return (fnvpair_value_int32(pair)); - - return (0); + return (error); } struct process_old_arg { @@ -473,23 +450,22 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, bool dmu_object_free_zapified(mos, obj, tx); } -static void +void dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx) { - dmu_snapshots_destroy_arg_t *dsda = arg; + dsl_destroy_snapshot_arg_t *ddsa = arg; + const char *dsname = ddsa->ddsa_name; + boolean_t defer = ddsa->ddsa_defer; + dsl_pool_t *dp = dmu_tx_pool(tx); - nvpair_t *pair; + dsl_dataset_t *ds; - for (pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, NULL); - pair != NULL; - pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, pair)) { - dsl_dataset_t *ds; - - VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds)); - - dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx); - dsl_dataset_rele(ds, FTAG); - } + int error = dsl_dataset_hold(dp, dsname, FTAG, &ds); + if (error == ENOENT) + return; + ASSERT0(error); + dsl_destroy_snapshot_sync_impl(ds, defer, tx); + dsl_dataset_rele(ds, FTAG); } /* @@ -509,25 +485,85 @@ int dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer, nvlist_t *errlist) { - dmu_snapshots_destroy_arg_t dsda; - int error; - nvpair_t *pair; - - pair = nvlist_next_nvpair(snaps, NULL); - if (pair == NULL) + if (nvlist_next_nvpair(snaps, NULL) == NULL) return (0); - dsda.dsda_snaps = snaps; - dsda.dsda_successful_snaps = fnvlist_alloc(); - dsda.dsda_defer = defer; - dsda.dsda_errlist = errlist; + nvlist_t *arg = fnvlist_alloc(); + nvlist_t *snaps_normalized = fnvlist_alloc(); + /* + * lzc_destroy_snaps() is documented to take an nvlist whose + * values "don't matter". We need to convert that nvlist to one + * that we know can be converted to LUA. + */ + for (nvpair_t *pair = nvlist_next_nvpair(snaps, NULL); + pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { + fnvlist_add_boolean_value(snaps_normalized, + nvpair_name(pair), B_TRUE); + } + fnvlist_add_nvlist(arg, "snaps", snaps_normalized); + fnvlist_add_boolean_value(arg, "defer", defer); - error = dsl_sync_task(nvpair_name(pair), - dsl_destroy_snapshot_check, dsl_destroy_snapshot_sync, - &dsda, 0, ZFS_SPACE_CHECK_NONE); - fnvlist_free(dsda.dsda_successful_snaps); + nvlist_t *wrapper = fnvlist_alloc(); + fnvlist_add_nvlist(wrapper, ZCP_ARG_ARGLIST, arg); + fnvlist_free(arg); - return (error); + const char *program = + "arg = ...\n" + "snaps = arg['snaps']\n" + "defer = arg['defer']\n" + "errors = { }\n" + "has_errors = false\n" + "for snap, v in pairs(snaps) do\n" + " errno = zfs.check.destroy{snap, defer=defer}\n" + " zfs.debug('snap: ' .. snap .. ' errno: ' .. errno)\n" + " if errno == ENOENT then\n" + " snaps[snap] = nil\n" + " elseif errno ~= 0 then\n" + " errors[snap] = errno\n" + " has_errors = true\n" + " end\n" + "end\n" + "if has_errors then\n" + " return errors\n" + "end\n" + "for snap, v in pairs(snaps) do\n" + " errno = zfs.sync.destroy{snap, defer=defer}\n" + " assert(errno == 0)\n" + "end\n" + "return { }\n"; + + nvlist_t *result = fnvlist_alloc(); + int error = zcp_eval(nvpair_name(nvlist_next_nvpair(snaps, NULL)), + program, + 0, + zfs_lua_max_memlimit, + fnvlist_lookup_nvpair(wrapper, ZCP_ARG_ARGLIST), result); + if (error != 0) { + char *errorstr = NULL; + (void) nvlist_lookup_string(result, ZCP_RET_ERROR, &errorstr); + if (errorstr != NULL) { + zfs_dbgmsg(errorstr); + } + return (error); + } *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709131045.v8DAjntu063845>