From 495daeba740c5e69192cb27ada89bb29de10c6af Mon Sep 17 00:00:00 2001 From: Justin Gibbs Date: Fri, 2 Oct 2015 10:41:02 -0700 Subject: [PATCH 01/40] Illumos 6267 - dn_bonus evicted too early The bonus buffer associated with a dnode is expected to remain resident until: the dnode is evicted via dnode_buf_pageout(), the dnode is freed in dnode_sync_free(), or the objset containing the dnode is evicted via dmu_objset_evict(). However, since bonus buffers (and DMU buffers in general) can have draining references when these events occur, dbuf_rele_and_unlock() has logic to ensure that once these late references are released affected buffers will be evicted. dbuf_rele_and_unlock() currently checks for a dbuf for an evicting objset via the os->os_evicting flag, and detects buffers for a freed dnode by testing dn->dn_type and dn->dn_free_txg fields. Unfortunately, the free'd dnode test can fire prematurely - anytime after the dnode is scheduled to be freed via dnode_free() until the free is committed in dnode_sync_free(). If all references to the bonus buffer are dropped within this window, the bonus buffer will be evicted and code in dnode_sync() that relies on the bonus buffer will fail. Additionally, the "free'd dnode test" isn't applied to normal buffers (buffers that are not the bonus buffer) and there is no mechanism to guarantee eviction in the dnode_buf_pageout() case (the dnode is not being freed nor is the objset being evicted). Replace the two existing deferred eviction mechanisms with a per-dbuf flag, db_pending_evict. This is set when explicit eviction is requested via either dnode_evict_dbufs() or dnode_evict_bonus(). These actions only occur after it is safe for dnode buffers to be evicted (e.g. the bonus buffer will not be referenced again). uts/common/fs/zfs/sys/dbuf.h: Add comments for boolean fields in dmu_buf_impl_t. Add the db_pending_evict field. uts/common/fs/zfs/sys/dbuf.h: uts/common/fs/zfs/dbuf.c: Rename db_immediate_evict to db_user_immediate_evict to avoid confusion between dbuf user state eviction and deferred eviction of a dbuf. uts/common/fs/zfs/dbuf.c: Consistently use TRUE/FALSE for boolean fields in dmu_buf_impl_t. Simplify pending eviction logic to use the new db_pending_evict flag in all cases. uts/common/fs/zfs/dmu_objset.c: uts/common/fs/zfs/sys/dmu_objset.h: Remove objset_t's os_evicting field. This same functionality is now provided by db_pending_evict. uts/common/fs/zfs/dnode_sync.c: In dnode_evict_dbufs() and dnode_evict_bonus(), mark dbufs with draining references (dbufs that can't be evicted inline) as pending_evict. In dnode_sync_free(), remove ASSERT() that a dnode being free'd has no active dbufs. This is usually the case, but is not guaranteed due to draining references. (e.g. The deadlist for a deleted dataset may still be open if another thread referenced the dataset just before it was freed and the dsl_dataset_t hasn't been released or is still being evicted). zfsonlinux/zfs#3865 zfsonlinux/zfs#3443 Ported-by: Ned Bass --- include/sys/dbuf.h | 18 ++++++++++++++- include/sys/dmu_objset.h | 1 - module/zfs/dbuf.c | 47 ++++++++++------------------------------ module/zfs/dmu_objset.c | 1 - module/zfs/dnode_sync.c | 14 +++++++----- 5 files changed, 38 insertions(+), 43 deletions(-) diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h index 94d326d5716c..f01326656c29 100644 --- a/include/sys/dbuf.h +++ b/include/sys/dbuf.h @@ -230,9 +230,25 @@ typedef struct dmu_buf_impl { /* User callback information. */ dmu_buf_user_t *db_user; - uint8_t db_immediate_evict; + /* + * Evict user data as soon as the dirty and reference + * counts are equal. + */ + uint8_t db_user_immediate_evict; + + /* + * This block was freed while a read or write was + * active. + */ uint8_t db_freed_in_flight; + /* + * dnode_evict_dbufs() or dnode_evict_bonsu() tried to + * evict this dbuf, but couldn't due to outstanding + * references. Evict once the refcount drops to 0. + */ + uint8_t db_pending_evict; + uint8_t db_dirtycnt; } dmu_buf_impl_t; diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h index bee4bbcfce03..837a0d5107b7 100644 --- a/include/sys/dmu_objset.h +++ b/include/sys/dmu_objset.h @@ -93,7 +93,6 @@ struct objset { uint8_t os_copies; enum zio_checksum os_dedup_checksum; boolean_t os_dedup_verify; - boolean_t os_evicting; zfs_logbias_op_t os_logbias; zfs_cache_type_t os_primary_cache; zfs_cache_type_t os_secondary_cache; diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index bab546c28d0c..d340da821fc5 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -303,7 +303,7 @@ dbuf_verify_user(dmu_buf_impl_t *db, dbvu_verify_type_t verify_type) */ ASSERT3U(holds, >=, db->db_dirtycnt); } else { - if (db->db_immediate_evict == TRUE) + if (db->db_user_immediate_evict == TRUE) ASSERT3U(holds, >=, db->db_dirtycnt); else ASSERT3U(holds, >, 0); @@ -1880,8 +1880,9 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid, db->db_blkptr = blkptr; db->db_user = NULL; - db->db_immediate_evict = 0; - db->db_freed_in_flight = 0; + db->db_user_immediate_evict = FALSE; + db->db_freed_in_flight = FALSE; + db->db_pending_evict = FALSE; if (blkid == DMU_BONUS_BLKID) { ASSERT3P(parent, ==, dn->dn_dbuf); @@ -2318,12 +2319,13 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag) arc_buf_freeze(db->db_buf); if (holds == db->db_dirtycnt && - db->db_level == 0 && db->db_immediate_evict) + db->db_level == 0 && db->db_user_immediate_evict) dbuf_evict_user(db); if (holds == 0) { if (db->db_blkid == DMU_BONUS_BLKID) { dnode_t *dn; + boolean_t evict_dbuf = db->db_pending_evict; /* * If the dnode moves here, we cannot cross this @@ -2338,7 +2340,7 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag) * Decrementing the dbuf count means that the bonus * buffer's dnode hold is no longer discounted in * dnode_move(). The dnode cannot move until after - * the dnode_rele_and_unlock() below. + * the dnode_rele() below. */ DB_DNODE_EXIT(db); @@ -2348,35 +2350,10 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag) */ mutex_exit(&db->db_mtx); - /* - * If the dnode has been freed, evict the bonus - * buffer immediately. The data in the bonus - * buffer is no longer relevant and this prevents - * a stale bonus buffer from being associated - * with this dnode_t should the dnode_t be reused - * prior to being destroyed. - */ - mutex_enter(&dn->dn_mtx); - if (dn->dn_type == DMU_OT_NONE || - dn->dn_free_txg != 0) { - /* - * Drop dn_mtx. It is a leaf lock and - * cannot be held when dnode_evict_bonus() - * acquires other locks in order to - * perform the eviction. - * - * Freed dnodes cannot be reused until the - * last hold is released. Since this bonus - * buffer has a hold, the dnode will remain - * in the free state, even without dn_mtx - * held, until the dnode_rele_and_unlock() - * below. - */ - mutex_exit(&dn->dn_mtx); + if (evict_dbuf) dnode_evict_bonus(dn); - mutex_enter(&dn->dn_mtx); - } - dnode_rele_and_unlock(dn, db); + + dnode_rele(dn, db); } else if (db->db_buf == NULL) { /* * This is a special case: we never associated this @@ -2423,7 +2400,7 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag) } else { dbuf_clear(db); } - } else if (db->db_objset->os_evicting || + } else if (db->db_pending_evict || arc_buf_eviction_needed(db->db_buf)) { dbuf_clear(db); } else { @@ -2471,7 +2448,7 @@ dmu_buf_set_user_ie(dmu_buf_t *db_fake, dmu_buf_user_t *user) { dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake; - db->db_immediate_evict = TRUE; + db->db_user_immediate_evict = TRUE; return (dmu_buf_set_user(db_fake, user)); } diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index b3168a856141..779b3bb789aa 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -726,7 +726,6 @@ dmu_objset_evict(objset_t *os) if (os->os_sa) sa_tear_down(os); - os->os_evicting = B_TRUE; dmu_objset_evict_dbufs(os); mutex_enter(&os->os_lock); diff --git a/module/zfs/dnode_sync.c b/module/zfs/dnode_sync.c index a8fa9a9527a9..df5c8e4ee6c4 100644 --- a/module/zfs/dnode_sync.c +++ b/module/zfs/dnode_sync.c @@ -432,6 +432,7 @@ dnode_evict_dbufs(dnode_t *dn) db_next = AVL_NEXT(&dn->dn_dbufs, db_marker); avl_remove(&dn->dn_dbufs, db_marker); } else { + db->db_pending_evict = TRUE; mutex_exit(&db->db_mtx); db_next = AVL_NEXT(&dn->dn_dbufs, db); } @@ -447,10 +448,14 @@ void dnode_evict_bonus(dnode_t *dn) { rw_enter(&dn->dn_struct_rwlock, RW_WRITER); - if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) { - mutex_enter(&dn->dn_bonus->db_mtx); - dbuf_evict(dn->dn_bonus); - dn->dn_bonus = NULL; + if (dn->dn_bonus != NULL) { + if (refcount_is_zero(&dn->dn_bonus->db_holds)) { + mutex_enter(&dn->dn_bonus->db_mtx); + dbuf_evict(dn->dn_bonus); + dn->dn_bonus = NULL; + } else { + dn->dn_bonus->db_pending_evict = TRUE; + } } rw_exit(&dn->dn_struct_rwlock); } @@ -502,7 +507,6 @@ dnode_sync_free(dnode_t *dn, dmu_tx_t *tx) dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]); dnode_evict_dbufs(dn); - ASSERT(avl_is_empty(&dn->dn_dbufs)); /* * XXX - It would be nice to assert this, but we may still From 48e41e86133a31add5f1006dfb16d586a64f5930 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 15 Sep 2015 13:49:44 -0400 Subject: [PATCH 02/40] Refactor dmu_objset_find_dp() to support a maximum depth and omit dsl_pool_t Signed-off-by: Richard Yao --- include/sys/dmu.h | 2 ++ include/sys/dmu_objset.h | 4 ++-- include/sys/zil.h | 8 ++++---- module/zfs/dmu_objset.c | 17 +++++++++++------ module/zfs/dsl_dataset.c | 15 +++++++-------- module/zfs/dsl_dir.c | 5 +++-- module/zfs/dsl_pool.c | 11 +++++++---- module/zfs/dsl_prop.c | 5 +++-- module/zfs/dsl_scan.c | 12 ++++++++---- module/zfs/spa.c | 5 +++-- module/zfs/zil.c | 6 ++++-- 11 files changed, 54 insertions(+), 36 deletions(-) diff --git a/include/sys/dmu.h b/include/sys/dmu.h index d9434db46383..baf07fb6790a 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -242,6 +242,8 @@ void zfs_znode_byteswap(void *buf, size_t size); #define DS_FIND_CHILDREN (1<<1) #define DS_FIND_SERIALIZE (1<<2) +#define DS_FIND_MAX_DEPTH (-1) + /* * The maximum number of bytes that can be accessed as part of one * operation, including metadata. diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h index 837a0d5107b7..10c4597d0d9a 100644 --- a/include/sys/dmu_objset.h +++ b/include/sys/dmu_objset.h @@ -154,8 +154,8 @@ void dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp, uint64_t *usedobjsp, uint64_t *availobjsp); uint64_t dmu_objset_fsid_guid(objset_t *os); int dmu_objset_find_dp(struct dsl_pool *dp, uint64_t ddobj, - int func(struct dsl_pool *, struct dsl_dataset *, void *), - void *arg, int flags); + int func(struct dsl_dataset *, boolean_t, void *), + void *arg, int flags, int depth); void dmu_objset_evict_dbufs(objset_t *os); timestruc_t dmu_objset_snap_cmtime(objset_t *os); diff --git a/include/sys/zil.h b/include/sys/zil.h index 65b14f1cd6a2..290480b4c612 100644 --- a/include/sys/zil.h +++ b/include/sys/zil.h @@ -469,10 +469,10 @@ extern void zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx); extern void zil_commit(zilog_t *zilog, uint64_t oid); extern int zil_vdev_offline(const char *osname, void *txarg); -extern int zil_claim(struct dsl_pool *dp, - struct dsl_dataset *ds, void *txarg); -extern int zil_check_log_chain(struct dsl_pool *dp, - struct dsl_dataset *ds, void *tx); +extern int zil_claim(struct dsl_dataset *ds, boolean_t unused, + void *txarg); +extern int zil_check_log_chain(struct dsl_dataset *ds, boolean_t unused, + void *tx); extern void zil_sync(zilog_t *zilog, dmu_tx_t *tx); extern void zil_clean(zilog_t *zilog, uint64_t synced_txg); diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 779b3bb789aa..79f8268f8153 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -1635,8 +1635,9 @@ typedef struct dmu_objset_find_ctx { taskq_t *dc_tq; dsl_pool_t *dc_dp; uint64_t dc_ddobj; - int (*dc_func)(dsl_pool_t *, dsl_dataset_t *, void *); + int (*dc_func)(dsl_dataset_t *, boolean_t, void *); void *dc_arg; + int dc_depth; int dc_flags; kmutex_t *dc_error_lock; int *dc_error; @@ -1674,7 +1675,7 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) /* * Iterate over all children. */ - if (dcp->dc_flags & DS_FIND_CHILDREN) { + if (dcp->dc_depth && dcp->dc_flags & DS_FIND_CHILDREN) { for (zap_cursor_init(&zc, dp->dp_meta_objset, dsl_dir_phys(dd)->dd_child_dir_zapobj); zap_cursor_retrieve(&zc, attr) == 0; @@ -1686,6 +1687,8 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) child_dcp = kmem_alloc(sizeof (*child_dcp), KM_SLEEP); *child_dcp = *dcp; child_dcp->dc_ddobj = attr->za_first_integer; + if (child_dcp->dc_depth != DS_FIND_MAX_DEPTH) + child_dcp->dc_depth--; if (dcp->dc_tq != NULL) (void) taskq_dispatch(dcp->dc_tq, dmu_objset_find_dp_cb, child_dcp, TQ_SLEEP); @@ -1698,7 +1701,7 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) /* * Iterate over all snapshots. */ - if (dcp->dc_flags & DS_FIND_SNAPSHOTS) { + if (dcp->dc_depth && dcp->dc_flags & DS_FIND_SNAPSHOTS) { dsl_dataset_t *ds; err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); @@ -1719,7 +1722,7 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) attr->za_first_integer, FTAG, &ds); if (err != 0) break; - err = dcp->dc_func(dp, ds, dcp->dc_arg); + err = dcp->dc_func(ds, B_FALSE, dcp->dc_arg); dsl_dataset_rele(ds, FTAG); if (err != 0) break; @@ -1740,7 +1743,7 @@ dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp) err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); if (err != 0) goto out; - err = dcp->dc_func(dp, ds, dcp->dc_arg); + err = dcp->dc_func(ds, dcp->dc_depth != 0, dcp->dc_arg); dsl_dataset_rele(ds, FTAG); out: @@ -1783,7 +1786,8 @@ dmu_objset_find_dp_cb(void *arg) */ int dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj, - int func(dsl_pool_t *, dsl_dataset_t *, void *), void *arg, int flags) + int func(dsl_dataset_t *, boolean_t, void *), void *arg, int flags, + int depth) { int error = 0; taskq_t *tq = NULL; @@ -1799,6 +1803,7 @@ dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj, dcp->dc_func = func; dcp->dc_arg = arg; dcp->dc_flags = flags; + dcp->dc_depth = depth; dcp->dc_error_lock = &err_lock; dcp->dc_error = &error; diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 2168f28941ed..7e62152a59a6 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -1788,8 +1788,7 @@ typedef struct dsl_dataset_rename_snapshot_arg { /* ARGSUSED */ static int -dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp, - dsl_dataset_t *hds, void *arg) +dsl_dataset_rename_snapshot_check_impl(dsl_dataset_t *hds, boolean_t unused, void *arg) { dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; int error; @@ -1831,19 +1830,19 @@ dsl_dataset_rename_snapshot_check(void *arg, dmu_tx_t *tx) if (ddrsa->ddrsa_recursive) { error = dmu_objset_find_dp(dp, hds->ds_dir->dd_object, dsl_dataset_rename_snapshot_check_impl, ddrsa, - DS_FIND_CHILDREN); + DS_FIND_CHILDREN, DS_FIND_MAX_DEPTH); } else { - error = dsl_dataset_rename_snapshot_check_impl(dp, hds, ddrsa); + error = dsl_dataset_rename_snapshot_check_impl(hds, B_FALSE, ddrsa); } dsl_dataset_rele(hds, FTAG); return (error); } static int -dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, - dsl_dataset_t *hds, void *arg) +dsl_dataset_rename_snapshot_sync_impl(dsl_dataset_t *hds, boolean_t unused, void *arg) { dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; + dsl_pool_t *dp = hds->ds_dir->dd_pool; dsl_dataset_t *ds; uint64_t val; dmu_tx_t *tx = ddrsa->ddrsa_tx; @@ -1887,9 +1886,9 @@ dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx) if (ddrsa->ddrsa_recursive) { VERIFY0(dmu_objset_find_dp(dp, hds->ds_dir->dd_object, dsl_dataset_rename_snapshot_sync_impl, ddrsa, - DS_FIND_CHILDREN)); + DS_FIND_CHILDREN, DS_FIND_MAX_DEPTH)); } else { - VERIFY0(dsl_dataset_rename_snapshot_sync_impl(dp, hds, ddrsa)); + VERIFY0(dsl_dataset_rename_snapshot_sync_impl(hds, B_FALSE, ddrsa)); } dsl_dataset_rele(hds, FTAG); } diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index ba6c24486463..9b41f2d47db9 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -1691,7 +1691,7 @@ typedef struct dsl_dir_rename_arg { /* ARGSUSED */ static int -dsl_valid_rename(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) +dsl_valid_rename(dsl_dataset_t *ds, boolean_t unused, void *arg) { int *deltap = arg; char namebuf[MAXNAMELEN]; @@ -1743,7 +1743,8 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx) /* if the name length is growing, validate child name lengths */ if (delta > 0) { error = dmu_objset_find_dp(dp, dd->dd_object, dsl_valid_rename, - &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); + &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS, + DS_FIND_MAX_DEPTH); if (error != 0) { dsl_dir_rele(newparent, FTAG); dsl_dir_rele(dd, FTAG); diff --git a/module/zfs/dsl_pool.c b/module/zfs/dsl_pool.c index ada0eac63eea..1c0014196a01 100644 --- a/module/zfs/dsl_pool.c +++ b/module/zfs/dsl_pool.c @@ -678,8 +678,9 @@ dsl_pool_undirty_space(dsl_pool_t *dp, int64_t space, uint64_t txg) /* ARGSUSED */ static int -upgrade_clones_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg) +upgrade_clones_cb(dsl_dataset_t *hds, boolean_t unused, void *arg) { + dsl_pool_t *dp = hds->ds_dir->dd_pool; dmu_tx_t *tx = arg; dsl_dataset_t *ds, *prev = NULL; int err; @@ -762,13 +763,14 @@ dsl_pool_upgrade_clones(dsl_pool_t *dp, dmu_tx_t *tx) ASSERT(dp->dp_origin_snap != NULL); VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj, upgrade_clones_cb, - tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE)); + tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE, DS_FIND_MAX_DEPTH)); } /* ARGSUSED */ static int -upgrade_dir_clones_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) +upgrade_dir_clones_cb(dsl_dataset_t *ds, boolean_t unused, void *arg) { + dsl_pool_t *dp = ds->ds_dir->dd_pool; dmu_tx_t *tx = arg; objset_t *mos = dp->dp_meta_objset; @@ -817,7 +819,8 @@ dsl_pool_upgrade_dir_clones(dsl_pool_t *dp, dmu_tx_t *tx) VERIFY0(bpobj_open(&dp->dp_free_bpobj, dp->dp_meta_objset, obj)); VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj, - upgrade_dir_clones_cb, tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE)); + upgrade_dir_clones_cb, tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE, + DS_FIND_MAX_DEPTH)); } void diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 28b101eee547..785f6695c0e1 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -431,8 +431,9 @@ dsl_prop_hascb(dsl_dataset_t *ds) /* ARGSUSED */ static int -dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) +dsl_prop_notify_all_cb(dsl_dataset_t *ds, boolean_t unused, void *arg) { + dsl_pool_t *dp = ds->ds_dir->dd_pool; dsl_dir_t *dd = ds->ds_dir; dsl_prop_cb_record_t *cbr; @@ -482,7 +483,7 @@ dsl_prop_notify_all(dsl_dir_t *dd) dsl_pool_t *dp = dd->dd_pool; ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb, - NULL, DS_FIND_CHILDREN); + NULL, DS_FIND_CHILDREN, DS_FIND_MAX_DEPTH); } static void diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index b989e763386b..6c8d34fbc04c 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -1021,8 +1021,9 @@ struct enqueue_clones_arg { /* ARGSUSED */ static int -enqueue_clones_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg) +enqueue_clones_cb(dsl_dataset_t *hds, boolean_t unused, void *arg) { + dsl_pool_t *dp = hds->ds_dir->dd_pool; struct enqueue_clones_arg *eca = arg; dsl_dataset_t *ds; int err; @@ -1148,7 +1149,8 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx) eca.originobj = ds->ds_object; VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj, - enqueue_clones_cb, &eca, DS_FIND_CHILDREN)); + enqueue_clones_cb, &eca, DS_FIND_CHILDREN, + DS_FIND_MAX_DEPTH)); } } @@ -1158,8 +1160,9 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx) /* ARGSUSED */ static int -enqueue_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg) +enqueue_cb(dsl_dataset_t *hds, boolean_t unused, void *arg) { + dsl_pool_t *dp = hds->ds_dir->dd_pool; dmu_tx_t *tx = arg; dsl_dataset_t *ds; int err; @@ -1324,7 +1327,8 @@ dsl_scan_visit(dsl_scan_t *scn, dmu_tx_t *tx) if (spa_version(dp->dp_spa) < SPA_VERSION_DSL_SCRUB) { VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj, - enqueue_cb, tx, DS_FIND_CHILDREN)); + enqueue_cb, tx, DS_FIND_CHILDREN, + DS_FIND_MAX_DEPTH)); } else { dsl_scan_visitds(scn, dp->dp_origin_snap->ds_object, tx); diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 2e23a341fb13..fe266a5b2969 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -1784,7 +1784,8 @@ spa_check_logs(spa_t *spa) /* need to recheck in case slog has been restored */ case SPA_LOG_UNKNOWN: rv = (dmu_objset_find_dp(dp, dp->dp_root_dir_obj, - zil_check_log_chain, NULL, DS_FIND_CHILDREN) != 0); + zil_check_log_chain, NULL, DS_FIND_CHILDREN, + DS_FIND_MAX_DEPTH) != 0); if (rv) spa_set_log_state(spa, SPA_LOG_MISSING); break; @@ -2784,7 +2785,7 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config, tx = dmu_tx_create_assigned(dp, spa_first_txg(spa)); (void) dmu_objset_find_dp(dp, dp->dp_root_dir_obj, - zil_claim, tx, DS_FIND_CHILDREN); + zil_claim, tx, DS_FIND_CHILDREN, DS_FIND_MAX_DEPTH); dmu_tx_commit(tx); spa->spa_claiming = B_FALSE; diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 289b23c7f488..175d2c66b4a4 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -660,8 +661,9 @@ zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx) } int -zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg) +zil_claim(dsl_dataset_t *ds, boolean_t unused, void *txarg) { + dsl_pool_t *dp = ds->ds_dir->dd_pool; dmu_tx_t *tx = txarg; uint64_t first_txg = dmu_tx_get_txg(tx); zilog_t *zilog; @@ -728,7 +730,7 @@ zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg) */ /* ARGSUSED */ int -zil_check_log_chain(dsl_pool_t *dp, dsl_dataset_t *ds, void *tx) +zil_check_log_chain(dsl_dataset_t *ds, boolean_t unused, void *tx) { zilog_t *zilog; objset_t *os; From ca22ac4ea049ee0f366b8f36b880196e51a21320 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 21 Jul 2015 13:36:23 -0400 Subject: [PATCH 03/40] Fix buffer overflow in zfs_ioc_recv The maximum name length is 256 without the NULL character, but we allocate a buffer that only has room for 255. Signed-off-by: Richard Yao --- module/zfs/zfs_ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 7ce19693e2d4..158278dd82d7 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -3998,7 +3998,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) nvlist_t *origprops = NULL; /* existing properties */ char *origin = NULL; char *tosnap; - char tofs[ZFS_MAXNAMELEN]; + char tofs[MAXNAMELEN + 1]; boolean_t first_recvd_props = B_FALSE; if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || @@ -4006,7 +4006,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) strchr(zc->zc_value, '%')) return (SET_ERROR(EINVAL)); - (void) strcpy(tofs, zc->zc_value); + (void) strlcpy(tofs, zc->zc_value, sizeof (tofs)); tosnap = strchr(tofs, '@'); *tosnap++ = '\0'; From 622ed4875fc2df6ca7011a263287531f79cac3c3 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 21 Jul 2015 11:17:05 -0400 Subject: [PATCH 04/40] dsl_dataset_rename_snapshot does not belong in sys/dmu.h Signed-off-by: Richard Yao --- include/sys/dmu.h | 2 -- module/zfs/zfs_ctldir.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/sys/dmu.h b/include/sys/dmu.h index baf07fb6790a..80aa2de4db94 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -280,8 +280,6 @@ int dmu_objset_snapshot_tmp(const char *, const char *, int); int dmu_objset_find(char *name, int func(const char *, void *), void *arg, int flags); void dmu_objset_byteswap(void *buf, size_t size); -int dsl_dataset_rename_snapshot(const char *fsname, - const char *oldsnapname, const char *newsnapname, boolean_t recursive); typedef struct dmu_buf { uint64_t db_object; /* object that this buffer is part of */ diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c index b70eb6623948..90bbe4eb276d 100644 --- a/module/zfs/zfs_ctldir.c +++ b/module/zfs/zfs_ctldir.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include From 18bf7a56b767c7743bd475efb53952a3fc56239a Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 21 Jul 2015 11:38:28 -0400 Subject: [PATCH 05/40] Rename length check should always be done Signed-off-by: Richard Yao --- module/zfs/dsl_dataset.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 7e62152a59a6..c6f966b31a83 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -1795,9 +1795,9 @@ dsl_dataset_rename_snapshot_check_impl(dsl_dataset_t *hds, boolean_t unused, voi uint64_t val; error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_oldsnapname, &val); - if (error != 0) { - /* ignore nonexistent snapshots */ - return (error == ENOENT ? 0 : error); + /* ignore nonexistent snapshots */ + if (error != 0 || error != ENOENT) { + return (error); } /* new name should not exist */ From 0311c756ef26cf04bee2a6f586c439217fc46f70 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Wed, 8 Jul 2015 11:28:50 -0400 Subject: [PATCH 06/40] lzc_snaprange_space fails to handle some edge cases well lzc_snaprange_space has a couple of bugs. One is that `usedp == NULL` will cause a segmentation fault. Another is that passing snapshots from different datasets will return ENOENT rather than EXDEV, which is inconsistent. This corrects that to make this more predictable. Signed-off-by: Richard Yao --- lib/libzfs_core/libzfs_core.c | 2 +- module/zfs/zfs_ioctl.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index b706e6f6be88..5da9cda9541c 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -311,7 +311,7 @@ lzc_snaprange_space(const char *firstsnap, const char *lastsnap, err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result); nvlist_free(args); - if (err == 0) + if (err == 0 && usedp != NULL) *usedp = fnvlist_lookup_uint64(result, "used"); fnvlist_free(result); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 158278dd82d7..0a23e6b75310 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5092,15 +5092,33 @@ zfs_ioc_space_written(zfs_cmd_t *zc) static int zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl) { - int error; + int error, len; dsl_pool_t *dp; dsl_dataset_t *new, *old; - char *firstsnap; + char *firstsnap, *sp; uint64_t used, comp, uncomp; if (nvlist_lookup_string(innvl, "firstsnap", &firstsnap) != 0) return (SET_ERROR(EINVAL)); + sp = strpbrk(firstsnap, "@#"); + if (sp == NULL) + return (SET_ERROR(EINVAL)); + if (*sp == '#') + return (SET_ERROR(EINVAL)); + len = sp - firstsnap; + + sp = strpbrk(lastsnap, "@#"); + if (sp == NULL) + return (SET_ERROR(EINVAL)); + if (*sp == '#') + return (SET_ERROR(EINVAL)); + + if (len != sp - firstsnap) + return (SET_ERROR(EXDEV)); + if (strncmp(lastsnap, firstsnap, len) != 0) + return (SET_ERROR(EXDEV)); + error = dsl_pool_hold(lastsnap, FTAG, &dp); if (error != 0) return (error); From ff9549b7eeca37ba6f5386ed14879904acce0f99 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 30 Sep 2015 12:35:28 +0300 Subject: [PATCH 07/40] zfs_ioc_space_snaps: fix a copy-paste error The error resulted in the incorrect comparison of the dataset base names. --- module/zfs/zfs_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 0a23e6b75310..e2deaee22667 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5114,7 +5114,7 @@ zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl) if (*sp == '#') return (SET_ERROR(EINVAL)); - if (len != sp - firstsnap) + if (len != sp - lastsnap) return (SET_ERROR(EXDEV)); if (strncmp(lastsnap, firstsnap, len) != 0) return (SET_ERROR(EXDEV)); From 6548fa19f391973c7398e3fe1fa9b7e693d82c12 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 21 Jul 2015 15:05:52 -0400 Subject: [PATCH 08/40] Implement new-style special property handling Currently, we have two types of properties. General properties that can be trivially updated in a single DMU transaction and special properties that implement their own handling and DMU transactions. Setting multiple properties can be set simultaneously requires that the special properties be refactored to share the DMU transaction of the regular properties. At present, the properties quota, refquota, reservation and refreservation are updated in the dsl_sync_task context much like the regular properties. They can be trivially refactored to be done in the same transaction group as the others, so we refactor them. The remaining snapdev, version, volsize and user properties are still handled separately. Refactoring them is non-trivial in comparison. To provide some specific points: volsize requires that calculate how much space needs to be freed when volume sizes are decreased in advance of calling `dsl_sync_task()`. If we have concurrent writers, this is non-trivial to do. version requires that we calculate how much space is needed when system attributes are added. It is not clear to me what the correct number is, so I err on the side of caution. snapdev has a TOCTOU race between the check and sync functions where the device might be opened. Attempting to set this in a manner intended to atomically set properties when we cannot atomically guarentee that we can always remove the device is an inconsistent behavior. The user properties were not inspected due to time constraints (and how rarely they are used). Signed-off-by: Richard Yao --- include/sys/dsl_dataset.h | 14 +++-- include/sys/dsl_dir.h | 17 ++++-- module/zfs/dsl_dataset.c | 118 ++++++++------------------------------ module/zfs/dsl_destroy.c | 2 +- module/zfs/dsl_dir.c | 113 +++++++++--------------------------- module/zfs/dsl_prop.c | 107 ++++++++++++++++++++++++++++++++++ module/zfs/zfs_ioctl.c | 12 ---- 7 files changed, 178 insertions(+), 205 deletions(-) diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index d6da5dcfdb9f..7ea900f7bc9c 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -272,10 +272,14 @@ int dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf); int dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv); -int dsl_dataset_set_refquota(const char *dsname, zprop_source_t source, - uint64_t quota); -int dsl_dataset_set_refreservation(const char *dsname, zprop_source_t source, - uint64_t reservation); +int dsl_dataset_set_refquota_check_impl(dsl_dataset_t *ds, + zprop_source_t source, uint64_t refquota, dmu_tx_t *tx); +void dsl_dataset_set_refquota_sync_impl(dsl_dataset_t *ds, + zprop_source_t source, uint64_t refquota, dmu_tx_t *tx); +int dsl_dataset_set_refreservation_check_impl(dsl_dataset_t *ds, + zprop_source_t source, uint64_t refreservation, dmu_tx_t *tx); +void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, + zprop_source_t source, uint64_t refreservation, dmu_tx_t *tx); boolean_t dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier, uint64_t earlier_txg); @@ -300,8 +304,6 @@ int dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value); int dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx, boolean_t adj_cnt); -void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, - zprop_source_t source, uint64_t value, dmu_tx_t *tx); void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx); int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result); diff --git a/include/sys/dsl_dir.h b/include/sys/dsl_dir.h index 55f3a8e5baa9..b16b1b2a3a28 100644 --- a/include/sys/dsl_dir.h +++ b/include/sys/dsl_dir.h @@ -121,6 +121,9 @@ dsl_dir_phys(dsl_dir_t *dd) return (dd->dd_dbuf->db_data); } +struct dsl_dataset; +typedef struct dsl_dataset dsl_dataset_t; + void dsl_dir_rele(dsl_dir_t *dd, void *tag); void dsl_dir_async_rele(dsl_dir_t *dd, void *tag); int dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag, @@ -145,10 +148,14 @@ void dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type, int64_t used, int64_t compressed, int64_t uncompressed, dmu_tx_t *tx); void dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta, dd_used_t oldtype, dd_used_t newtype, dmu_tx_t *tx); -int dsl_dir_set_quota(const char *ddname, zprop_source_t source, - uint64_t quota); -int dsl_dir_set_reservation(const char *ddname, zprop_source_t source, - uint64_t reservation); +int dsl_dir_set_quota_check_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t quota, dmu_tx_t *tx); +void dsl_dir_set_quota_sync_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t quota, dmu_tx_t *tx); +int dsl_dir_set_reservation_check_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t reservation, dmu_tx_t *tx); +void dsl_dir_set_reservation_sync_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t reservation, dmu_tx_t *tx); int dsl_dir_activate_fs_ss_limit(const char *); int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *, cred_t *); @@ -161,7 +168,7 @@ void dsl_dir_new_refreservation(dsl_dir_t *dd, struct dsl_dataset *ds, uint64_t reservation, cred_t *cr, dmu_tx_t *tx); void dsl_dir_snap_cmtime_update(dsl_dir_t *dd); timestruc_t dsl_dir_snap_cmtime(dsl_dir_t *dd); -void dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value, +void dsl_dir_set_reservation_sync_impl_impl(dsl_dir_t *dd, uint64_t value, dmu_tx_t *tx); void dsl_dir_zapify(dsl_dir_t *dd, dmu_tx_t *tx); boolean_t dsl_dir_is_zapified(dsl_dir_t *dd); diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index c6f966b31a83..3dcaed0e873a 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -1788,7 +1788,8 @@ typedef struct dsl_dataset_rename_snapshot_arg { /* ARGSUSED */ static int -dsl_dataset_rename_snapshot_check_impl(dsl_dataset_t *hds, boolean_t unused, void *arg) +dsl_dataset_rename_snapshot_check_impl(dsl_dataset_t *hds, boolean_t unused, + void *arg) { dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; int error; @@ -1832,14 +1833,16 @@ dsl_dataset_rename_snapshot_check(void *arg, dmu_tx_t *tx) dsl_dataset_rename_snapshot_check_impl, ddrsa, DS_FIND_CHILDREN, DS_FIND_MAX_DEPTH); } else { - error = dsl_dataset_rename_snapshot_check_impl(hds, B_FALSE, ddrsa); + error = dsl_dataset_rename_snapshot_check_impl(hds, B_FALSE, + ddrsa); } dsl_dataset_rele(hds, FTAG); return (error); } static int -dsl_dataset_rename_snapshot_sync_impl(dsl_dataset_t *hds, boolean_t unused, void *arg) +dsl_dataset_rename_snapshot_sync_impl(dsl_dataset_t *hds, boolean_t unused, + void *arg) { dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; dsl_pool_t *dp = hds->ds_dir->dd_pool; @@ -1888,7 +1891,8 @@ dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx) dsl_dataset_rename_snapshot_sync_impl, ddrsa, DS_FIND_CHILDREN, DS_FIND_MAX_DEPTH)); } else { - VERIFY0(dsl_dataset_rename_snapshot_sync_impl(hds, B_FALSE, ddrsa)); + VERIFY0(dsl_dataset_rename_snapshot_sync_impl(hds, B_FALSE, + ddrsa)); } dsl_dataset_rele(hds, FTAG); } @@ -2906,72 +2910,51 @@ dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, return (error); } -typedef struct dsl_dataset_set_qr_arg { - const char *ddsqra_name; - zprop_source_t ddsqra_source; - uint64_t ddsqra_value; -} dsl_dataset_set_qr_arg_t; - - /* ARGSUSED */ -static int -dsl_dataset_set_refquota_check(void *arg, dmu_tx_t *tx) +int +dsl_dataset_set_refquota_check_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t refquota, dmu_tx_t *tx) { - dsl_dataset_set_qr_arg_t *ddsqra = arg; dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; int error; uint64_t newval; if (spa_version(dp->dp_spa) < SPA_VERSION_REFQUOTA) return (SET_ERROR(ENOTSUP)); - error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds); - if (error != 0) - return (error); - - if (ds->ds_is_snapshot) { - dsl_dataset_rele(ds, FTAG); + if (dsl_dataset_is_snapshot(ds)) { return (SET_ERROR(EINVAL)); } error = dsl_prop_predict(ds->ds_dir, zfs_prop_to_name(ZFS_PROP_REFQUOTA), - ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval); + source, refquota, &newval); if (error != 0) { - dsl_dataset_rele(ds, FTAG); return (error); } if (newval == 0) { - dsl_dataset_rele(ds, FTAG); return (0); } if (newval < dsl_dataset_phys(ds)->ds_referenced_bytes || newval < ds->ds_reserved) { - dsl_dataset_rele(ds, FTAG); return (SET_ERROR(ENOSPC)); } - dsl_dataset_rele(ds, FTAG); return (0); } -static void -dsl_dataset_set_refquota_sync(void *arg, dmu_tx_t *tx) +void +dsl_dataset_set_refquota_sync_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t refquota, dmu_tx_t *tx) { - dsl_dataset_set_qr_arg_t *ddsqra = arg; - dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; uint64_t newval; - VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds)); - dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_REFQUOTA), - ddsqra->ddsqra_source, sizeof (ddsqra->ddsqra_value), 1, - &ddsqra->ddsqra_value, tx); + source, sizeof (refquota), 1, + &refquota, tx); VERIFY0(dsl_prop_get_int_ds(ds, zfs_prop_to_name(ZFS_PROP_REFQUOTA), &newval)); @@ -2980,49 +2963,27 @@ dsl_dataset_set_refquota_sync(void *arg, dmu_tx_t *tx) dmu_buf_will_dirty(ds->ds_dbuf, tx); ds->ds_quota = newval; } - dsl_dataset_rele(ds, FTAG); } int -dsl_dataset_set_refquota(const char *dsname, zprop_source_t source, - uint64_t refquota) -{ - dsl_dataset_set_qr_arg_t ddsqra; - - ddsqra.ddsqra_name = dsname; - ddsqra.ddsqra_source = source; - ddsqra.ddsqra_value = refquota; - - return (dsl_sync_task(dsname, dsl_dataset_set_refquota_check, - dsl_dataset_set_refquota_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE)); -} - -static int -dsl_dataset_set_refreservation_check(void *arg, dmu_tx_t *tx) +dsl_dataset_set_refreservation_check_impl(dsl_dataset_t *ds, + zprop_source_t source, uint64_t refreservation, dmu_tx_t *tx) { - dsl_dataset_set_qr_arg_t *ddsqra = arg; dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; int error; uint64_t newval, unique; if (spa_version(dp->dp_spa) < SPA_VERSION_REFRESERVATION) return (SET_ERROR(ENOTSUP)); - error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds); - if (error != 0) - return (error); - - if (ds->ds_is_snapshot) { - dsl_dataset_rele(ds, FTAG); + if (dsl_dataset_is_snapshot(ds)) { return (SET_ERROR(EINVAL)); } error = dsl_prop_predict(ds->ds_dir, zfs_prop_to_name(ZFS_PROP_REFRESERVATION), - ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval); + source, refreservation, &newval); if (error != 0) { - dsl_dataset_rele(ds, FTAG); return (error); } @@ -3031,7 +2992,6 @@ dsl_dataset_set_refreservation_check(void *arg, dmu_tx_t *tx) * space estimates may be inaccurate. */ if (!dmu_tx_is_syncing(tx)) { - dsl_dataset_rele(ds, FTAG); return (0); } @@ -3048,25 +3008,23 @@ dsl_dataset_set_refreservation_check(void *arg, dmu_tx_t *tx) if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, B_TRUE) || (ds->ds_quota > 0 && newval > ds->ds_quota)) { - dsl_dataset_rele(ds, FTAG); return (SET_ERROR(ENOSPC)); } } - dsl_dataset_rele(ds, FTAG); return (0); } void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, - zprop_source_t source, uint64_t value, dmu_tx_t *tx) + zprop_source_t source, uint64_t refreservation, dmu_tx_t *tx) { uint64_t newval; uint64_t unique; int64_t delta; dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_REFRESERVATION), - source, sizeof (value), 1, &value, tx); + source, sizeof (refreservation), 1, &refreservation, tx); VERIFY0(dsl_prop_get_int_ds(ds, zfs_prop_to_name(ZFS_PROP_REFRESERVATION), &newval)); @@ -3085,34 +3043,6 @@ dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, mutex_exit(&ds->ds_dir->dd_lock); } -static void -dsl_dataset_set_refreservation_sync(void *arg, dmu_tx_t *tx) -{ - dsl_dataset_set_qr_arg_t *ddsqra = arg; - dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; - - VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds)); - dsl_dataset_set_refreservation_sync_impl(ds, - ddsqra->ddsqra_source, ddsqra->ddsqra_value, tx); - dsl_dataset_rele(ds, FTAG); -} - -int -dsl_dataset_set_refreservation(const char *dsname, zprop_source_t source, - uint64_t refreservation) -{ - dsl_dataset_set_qr_arg_t ddsqra; - - ddsqra.ddsqra_name = dsname; - ddsqra.ddsqra_source = source; - ddsqra.ddsqra_value = refreservation; - - return (dsl_sync_task(dsname, dsl_dataset_set_refreservation_check, - dsl_dataset_set_refreservation_sync, &ddsqra, - 0, ZFS_SPACE_CHECK_NONE)); -} - /* * Return (in *usedp) the amount of space written in new that is not * present in oldsnap. New may be a snapshot or the head. Old must be diff --git a/module/zfs/dsl_destroy.c b/module/zfs/dsl_destroy.c index 0e2238f99e51..0145a3c795d4 100644 --- a/module/zfs/dsl_destroy.c +++ b/module/zfs/dsl_destroy.c @@ -693,7 +693,7 @@ dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx) * Remove our reservation. The impl() routine avoids setting the * actual property, which would require the (already destroyed) ds. */ - dsl_dir_set_reservation_sync_impl(dd, 0, tx); + dsl_dir_set_reservation_sync_impl_impl(dd, 0, tx); ASSERT0(dsl_dir_phys(dd)->dd_used_bytes); ASSERT0(dsl_dir_phys(dd)->dd_reserved); diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 9b41f2d47db9..ac657b30d910 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -1366,7 +1366,7 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type, int64_t accounted_delta; /* - * dsl_dataset_set_refreservation_sync_impl() calls this with + * dsl_dataset_set_refreservation_sync_impl_impl() calls this with * dd_lock held, so that it can atomically update * ds->ds_reserved and the dsl_dir accounting, so that * dsl_dataset_check_quota() can see dataset and dir accounting @@ -1441,34 +1441,20 @@ dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta, mutex_exit(&dd->dd_lock); } -typedef struct dsl_dir_set_qr_arg { - const char *ddsqra_name; - zprop_source_t ddsqra_source; - uint64_t ddsqra_value; -} dsl_dir_set_qr_arg_t; - -static int -dsl_dir_set_quota_check(void *arg, dmu_tx_t *tx) +int +dsl_dir_set_quota_check_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t quota, dmu_tx_t *tx) { - dsl_dir_set_qr_arg_t *ddsqra = arg; - dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; int error; uint64_t towrite, newval; - error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds); - if (error != 0) - return (error); - error = dsl_prop_predict(ds->ds_dir, "quota", - ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval); + source, quota, &newval); if (error != 0) { - dsl_dataset_rele(ds, FTAG); return (error); } if (newval == 0) { - dsl_dataset_rele(ds, FTAG); return (0); } @@ -1486,29 +1472,25 @@ dsl_dir_set_quota_check(void *arg, dmu_tx_t *tx) error = SET_ERROR(ENOSPC); } mutex_exit(&ds->ds_dir->dd_lock); - dsl_dataset_rele(ds, FTAG); return (error); } -static void -dsl_dir_set_quota_sync(void *arg, dmu_tx_t *tx) +void +dsl_dir_set_quota_sync_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t quota, dmu_tx_t *tx) { - dsl_dir_set_qr_arg_t *ddsqra = arg; dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; uint64_t newval; - VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds)); - if (spa_version(dp->dp_spa) >= SPA_VERSION_RECVD_PROPS) { dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_QUOTA), - ddsqra->ddsqra_source, sizeof (ddsqra->ddsqra_value), 1, - &ddsqra->ddsqra_value, tx); + source, sizeof (quota), 1, + "a, tx); VERIFY0(dsl_prop_get_int_ds(ds, zfs_prop_to_name(ZFS_PROP_QUOTA), &newval)); } else { - newval = ddsqra->ddsqra_value; + newval = quota; spa_history_log_internal_ds(ds, "set", tx, "%s=%lld", zfs_prop_to_name(ZFS_PROP_QUOTA), (longlong_t)newval); } @@ -1517,35 +1499,16 @@ dsl_dir_set_quota_sync(void *arg, dmu_tx_t *tx) mutex_enter(&ds->ds_dir->dd_lock); dsl_dir_phys(ds->ds_dir)->dd_quota = newval; mutex_exit(&ds->ds_dir->dd_lock); - dsl_dataset_rele(ds, FTAG); -} - -int -dsl_dir_set_quota(const char *ddname, zprop_source_t source, uint64_t quota) -{ - dsl_dir_set_qr_arg_t ddsqra; - - ddsqra.ddsqra_name = ddname; - ddsqra.ddsqra_source = source; - ddsqra.ddsqra_value = quota; - - return (dsl_sync_task(ddname, dsl_dir_set_quota_check, - dsl_dir_set_quota_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE)); } int -dsl_dir_set_reservation_check(void *arg, dmu_tx_t *tx) +dsl_dir_set_reservation_check_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t reservation, dmu_tx_t *tx) { - dsl_dir_set_qr_arg_t *ddsqra = arg; - dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; dsl_dir_t *dd; uint64_t newval, used, avail; int error; - error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds); - if (error != 0) - return (error); dd = ds->ds_dir; /* @@ -1553,15 +1516,13 @@ dsl_dir_set_reservation_check(void *arg, dmu_tx_t *tx) * space estimates may be inaccurate. */ if (!dmu_tx_is_syncing(tx)) { - dsl_dataset_rele(ds, FTAG); return (0); } error = dsl_prop_predict(ds->ds_dir, zfs_prop_to_name(ZFS_PROP_RESERVATION), - ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval); + source, reservation, &newval); if (error != 0) { - dsl_dataset_rele(ds, FTAG); return (error); } @@ -1586,12 +1547,12 @@ dsl_dir_set_reservation_check(void *arg, dmu_tx_t *tx) error = SET_ERROR(ENOSPC); } - dsl_dataset_rele(ds, FTAG); return (error); } void -dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value, dmu_tx_t *tx) +dsl_dir_set_reservation_sync_impl_impl(dsl_dir_t *dd, uint64_t reservation, + dmu_tx_t *tx) { uint64_t used; int64_t delta; @@ -1600,8 +1561,9 @@ dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value, dmu_tx_t *tx) mutex_enter(&dd->dd_lock); used = dsl_dir_phys(dd)->dd_used_bytes; - delta = MAX(used, value) - MAX(used, dsl_dir_phys(dd)->dd_reserved); - dsl_dir_phys(dd)->dd_reserved = value; + delta = MAX(used, reservation) - MAX(used, + dsl_dir_phys(dd)->dd_reserved); + dsl_dir_phys(dd)->dd_reserved = reservation; if (dd->dd_parent != NULL) { /* Roll up this additional usage into our ancestors */ @@ -1611,47 +1573,29 @@ dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value, dmu_tx_t *tx) mutex_exit(&dd->dd_lock); } -static void -dsl_dir_set_reservation_sync(void *arg, dmu_tx_t *tx) +void +dsl_dir_set_reservation_sync_impl(dsl_dataset_t *ds, zprop_source_t source, + uint64_t reservation, dmu_tx_t *tx) { - dsl_dir_set_qr_arg_t *ddsqra = arg; dsl_pool_t *dp = dmu_tx_pool(tx); - dsl_dataset_t *ds; uint64_t newval; - VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds)); - if (spa_version(dp->dp_spa) >= SPA_VERSION_RECVD_PROPS) { dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_RESERVATION), - ddsqra->ddsqra_source, sizeof (ddsqra->ddsqra_value), 1, - &ddsqra->ddsqra_value, tx); + source, sizeof (reservation), 1, + &reservation, tx); VERIFY0(dsl_prop_get_int_ds(ds, zfs_prop_to_name(ZFS_PROP_RESERVATION), &newval)); } else { - newval = ddsqra->ddsqra_value; + newval = reservation; spa_history_log_internal_ds(ds, "set", tx, "%s=%lld", zfs_prop_to_name(ZFS_PROP_RESERVATION), (longlong_t)newval); } - dsl_dir_set_reservation_sync_impl(ds->ds_dir, newval, tx); - dsl_dataset_rele(ds, FTAG); -} - -int -dsl_dir_set_reservation(const char *ddname, zprop_source_t source, - uint64_t reservation) -{ - dsl_dir_set_qr_arg_t ddsqra; - - ddsqra.ddsqra_name = ddname; - ddsqra.ddsqra_source = source; - ddsqra.ddsqra_value = reservation; - - return (dsl_sync_task(ddname, dsl_dir_set_reservation_check, - dsl_dir_set_reservation_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE)); + dsl_dir_set_reservation_sync_impl_impl(ds->ds_dir, newval, tx); } static dsl_dir_t * @@ -2003,8 +1947,3 @@ dsl_dir_is_zapified(dsl_dir_t *dd) dmu_object_info_from_db(dd->dd_dbuf, &doi); return (doi.doi_type == DMU_OTN_ZAP_METADATA); } - -#if defined(_KERNEL) && defined(HAVE_SPL) -EXPORT_SYMBOL(dsl_dir_set_quota); -EXPORT_SYMBOL(dsl_dir_set_reservation); -#endif diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 785f6695c0e1..cc7b80a4a4ab 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -759,6 +759,104 @@ typedef struct dsl_props_set_arg { nvlist_t *dpsa_props; } dsl_props_set_arg_t; +static int +dsl_props_set_special_check(dsl_dataset_t *ds, zprop_source_t source, + nvpair_t *pair, dmu_tx_t *tx) +{ + const char *propname = nvpair_name(pair); + zfs_prop_t prop = zfs_name_to_prop(propname); + uint64_t intval; + char *strval; + int err = 0; + + switch (nvpair_type(pair)) { + case DATA_TYPE_STRING: + if (nvpair_value_string(pair, &strval) != 0) + return (SET_ERROR(EINVAL)); + if (zfs_prop_get_type(prop) == PROP_TYPE_INDEX && + zfs_prop_string_to_index(prop, strval, &intval) != 0) + return (SET_ERROR(EINVAL)); + break; + case DATA_TYPE_UINT64: + VERIFY(0 == nvpair_value_uint64(pair, &intval)); + default: + break; + } + + switch (prop) { + case ZFS_PROP_QUOTA: + err = dsl_dir_set_quota_check_impl(ds, source, intval, tx); + break; + case ZFS_PROP_REFQUOTA: + err = dsl_dataset_set_refquota_check_impl(ds, source, intval, tx); + break; + case ZFS_PROP_RESERVATION: + err = dsl_dir_set_reservation_check_impl(ds, source, intval, tx); + break; + case ZFS_PROP_REFRESERVATION: + err = dsl_dataset_set_refreservation_check_impl(ds, source, intval, + tx); + break; + case ZFS_PROP_VOLSIZE: + case ZFS_PROP_SNAPDEV: + case ZFS_PROP_VERSION: + default: + break; + } + + return (err); + +} + +static boolean_t +dsl_props_set_special_sync(dsl_dataset_t *ds, zprop_source_t source, + nvpair_t *pair, dmu_tx_t *tx) +{ + const char *propname = nvpair_name(pair); + zfs_prop_t prop = zfs_name_to_prop(propname); + uint64_t intval; + char *strval; + + switch (nvpair_type(pair)) { + case DATA_TYPE_STRING: + if (nvpair_value_string(pair, &strval) != 0) + return (SET_ERROR(EINVAL)); + if (!zfs_prop_user(propname) && + zfs_prop_get_type(prop) == PROP_TYPE_INDEX && + zfs_prop_string_to_index(prop, strval, &intval) != 0) + return (SET_ERROR(EINVAL)); + break; + case DATA_TYPE_UINT64: + VERIFY0(nvpair_value_uint64(pair, &intval)); + break; + default: + return (B_FALSE); + } + + switch (prop) { + case ZFS_PROP_QUOTA: + dsl_dir_set_quota_sync_impl(ds, source, intval, tx); + break; + case ZFS_PROP_REFQUOTA: + dsl_dataset_set_refquota_sync_impl(ds, source, intval, tx); + break; + case ZFS_PROP_RESERVATION: + dsl_dir_set_reservation_sync_impl(ds, source, intval, tx); + break; + case ZFS_PROP_REFRESERVATION: + dsl_dataset_set_refreservation_sync_impl(ds, source, intval, tx); + break; + case ZFS_PROP_VOLSIZE: + case ZFS_PROP_SNAPDEV: + case ZFS_PROP_VERSION: + default: + return (B_FALSE); + } + + return (B_TRUE); + +} + static int dsl_props_set_check(void *arg, dmu_tx_t *tx) { @@ -788,6 +886,12 @@ dsl_props_set_check(void *arg, dmu_tx_t *tx) return (E2BIG); } } + + if ((err = dsl_props_set_special_check(ds, dpsa->dpsa_source, + elem, tx))) { + dsl_dataset_rele(ds, FTAG); + return (err); + } } if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) { @@ -816,6 +920,9 @@ dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source, pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE); } + if (dsl_props_set_special_sync(ds, source, pair, tx)) + continue; + if (nvpair_type(pair) == DATA_TYPE_STRING) { const char *value = fnvpair_value_string(pair); dsl_prop_set_sync_impl(ds, nvpair_name(pair), diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index e2deaee22667..0a6bb4e1a50a 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2364,12 +2364,6 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, VERIFY(0 == nvpair_value_uint64(pair, &intval)); switch (prop) { - case ZFS_PROP_QUOTA: - err = dsl_dir_set_quota(dsname, source, intval); - break; - case ZFS_PROP_REFQUOTA: - err = dsl_dataset_set_refquota(dsname, source, intval); - break; case ZFS_PROP_FILESYSTEM_LIMIT: case ZFS_PROP_SNAPSHOT_LIMIT: if (intval == UINT64_MAX) { @@ -2385,12 +2379,6 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, if (err == 0) err = -1; break; - case ZFS_PROP_RESERVATION: - err = dsl_dir_set_reservation(dsname, source, intval); - break; - case ZFS_PROP_REFRESERVATION: - err = dsl_dataset_set_refreservation(dsname, source, intval); - break; case ZFS_PROP_VOLSIZE: err = zvol_set_volsize(dsname, intval); break; From 7b21d100aa8d1eeb727a47b8c6226fe0f7d448ce Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 6 Feb 2015 16:17:44 -0500 Subject: [PATCH 09/40] Refactor zfs_ioc_dataset_list_next() to stop passing around zfs_command_t Signed-off-by: Richard Yao --- module/zfs/zfs_ioctl.c | 230 +++++++++++++++++++++++++++++++---------- 1 file changed, 173 insertions(+), 57 deletions(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 0a6bb4e1a50a..f721e45d72e4 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -72,7 +72,7 @@ * name, a dataset name, or nothing. If the name is not well-formed, * the ioctl will fail and the callback will not be called. * Therefore, the callback can assume that the name is well-formed - * (e.g. is null-terminated, doesn't have more than one '@' character, + * (e.g. is NULL-terminated, doesn't have more than one '@' character, * doesn't have invalid characters). * * zfs_ioc_poolcheck_t pool_check @@ -1993,17 +1993,28 @@ zfs_ioc_vdev_setfru(zfs_cmd_t *zc) return (error); } +/* + * inputs: + * nv nvlist handle + * stat pointer to dmu_objset_stats_t for output + * os Objset of filesystem (held by caller) + * + * outputs: + * *nv property nvlist + * *stat updated stats + * + * The caller frees the nvlist on success. + */ static int -zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) +zfs_ioc_objset_stats_impl_nohold(nvlist_t **nv, dmu_objset_stats_t *stat, + objset_t *os, boolean_t str_indices) { int error = 0; - nvlist_t *nv; - dmu_objset_fast_stat(os, &zc->zc_objset_stats); + dmu_objset_fast_stat(os, stat); - if (zc->zc_nvlist_dst != 0 && - (error = dsl_prop_get_all(os, &nv)) == 0) { - dmu_objset_stats(os, nv); + if (nv != 0 && (error = dsl_prop_get_all(os, nv)) == 0) { + dmu_objset_stats(os, *nv); /* * NB: zvol_get_stats() will read the objset contents, * which we aren't supposed to do with a @@ -2011,21 +2022,39 @@ zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) * inconsistent. So this is a bit of a workaround... * XXX reading with out owning */ - if (!zc->zc_objset_stats.dds_inconsistent && + if (!stat->dds_inconsistent && dmu_objset_type(os) == DMU_OST_ZVOL) { - error = zvol_get_stats(os, nv); + error = zvol_get_stats(os, *nv); + if (error) + nvlist_free(*nv); if (error == EIO) return (error); VERIFY0(error); } - if (error == 0) - error = put_nvlist(zc, nv); - nvlist_free(nv); } return (error); } +static int +zfs_ioc_objset_stats_impl(nvlist_t **nvp, dmu_objset_stats_t *stat, + char *fsname, boolean_t str_indices) +{ + objset_t *os; + int error; + + error = dmu_objset_hold(fsname, FTAG, &os); + if (error == 0) { + error = zfs_ioc_objset_stats_impl_nohold(nvp, stat, + os, str_indices); + + dmu_objset_rele(os, FTAG); + } + + + return (error); +} + /* * inputs: * zc_name name of filesystem @@ -2039,13 +2068,18 @@ zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os) static int zfs_ioc_objset_stats(zfs_cmd_t *zc) { - objset_t *os; + nvlist_t *nv = NULL; + nvlist_t **nvp = (zc->zc_nvlist_dst) ? &nv : NULL; int error; - error = dmu_objset_hold(zc->zc_name, FTAG, &os); - if (error == 0) { - error = zfs_ioc_objset_stats_impl(zc, os); - dmu_objset_rele(os, FTAG); + error = zfs_ioc_objset_stats_impl(nvp, &zc->zc_objset_stats, + zc->zc_name, B_FALSE); + + if (nv) { + if (error == 0) { + error = put_nvlist(zc, *nvp); + } + nvlist_free(nv); } return (error); @@ -2165,57 +2199,65 @@ dataset_name_hidden(const char *name) return (B_FALSE); } +typedef struct zfs_list { + char *zl_name; + uint64_t zl_cookie; + uint64_t zl_obj; + dmu_objset_stats_t *zl_objset_stats; + nvlist_t *zl_nvlist; +} zfs_list_t; + /* * inputs: - * zc_name name of filesystem - * zc_cookie zap cursor - * zc_nvlist_dst_size size of buffer for property nvlist + * zl_name name of filesystem + * zl_cookie zap cursor * * outputs: - * zc_name name of next filesystem - * zc_cookie zap cursor - * zc_objset_stats stats - * zc_nvlist_dst property nvlist - * zc_nvlist_dst_size size of property nvlist + * zl_name name of next filesystem + * zl_cookie zap cursor + * zl_objset_stats stats + * zl_nvlist property nvlist */ -static int -zfs_ioc_dataset_list_next(zfs_cmd_t *zc) +int +zfs_ioc_dataset_list_next_impl(zfs_list_t *zl) { objset_t *os; int error; char *p; - size_t orig_len = strlen(zc->zc_name); + size_t orig_len = strlen(zl->zl_name); top: - if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os))) { + if ((error = dmu_objset_hold(zl->zl_name, FTAG, &os))) { if (error == ENOENT) error = SET_ERROR(ESRCH); return (error); } - p = strrchr(zc->zc_name, '/'); + p = strrchr(zl->zl_name, '/'); if (p == NULL || p[1] != '\0') - (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); - p = zc->zc_name + strlen(zc->zc_name); + (void) strlcat(zl->zl_name, "/", sizeof (zl->zl_name)); + p = zl->zl_name + strlen(zl->zl_name); do { error = dmu_dir_list_next(os, - sizeof (zc->zc_name) - (p - zc->zc_name), p, - NULL, &zc->zc_cookie); + sizeof (zl->zl_name) - (p - zl->zl_name), p, + NULL, &zl->zl_cookie); if (error == ENOENT) error = SET_ERROR(ESRCH); - } while (error == 0 && dataset_name_hidden(zc->zc_name)); + } while (error == 0 && dataset_name_hidden(zl->zl_name)); dmu_objset_rele(os, FTAG); /* - * If it's an internal dataset (ie. with a '$' in its name), + * 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(zc->zc_name, '$') == NULL) { - error = zfs_ioc_objset_stats(zc); /* fill in the stats */ + if (error == 0 && strchr(zl->zl_name, '$') == NULL) { + /* fill in the stats */ + error = zfs_ioc_objset_stats_impl(&zl->zl_nvlist, + zl->zl_objset_stats, zl->zl_name, B_FALSE); if (error == ENOENT) { - /* We lost a race with destroy, get the next one. */ - zc->zc_name[orig_len] = '\0'; + /* we lost a race with destroy, get the next one. */ + zl->zl_name[orig_len] = '\0'; goto top; } } @@ -2224,23 +2266,22 @@ zfs_ioc_dataset_list_next(zfs_cmd_t *zc) /* * inputs: - * zc_name name of filesystem - * zc_cookie zap cursor - * zc_nvlist_dst_size size of buffer for property nvlist + * zl_name name of filesystem + * zl_cookie zap cursor + * simple whether ot grab objset_stats * * outputs: - * zc_name name of next snapshot - * zc_objset_stats stats - * zc_nvlist_dst property nvlist - * zc_nvlist_dst_size size of property nvlist + * zl_name name of next snapshot + * zl_objset_stats stats + * zl_nvlist property nvlist */ static int -zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) +zfs_ioc_snapshot_list_next_impl(zfs_list_t *zl, boolean_t simple) { objset_t *os; int error; - error = dmu_objset_hold(zc->zc_name, FTAG, &os); + error = dmu_objset_hold(zl->zl_name, FTAG, &os); if (error != 0) { return (error == ENOENT ? ESRCH : error); } @@ -2249,28 +2290,36 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) * A dataset name of maximum length cannot have any snapshots, * so exit immediately. */ - if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { + if (strlcat(zl->zl_name, "@", sizeof (zl->zl_name)) >= MAXNAMELEN) { dmu_objset_rele(os, FTAG); return (SET_ERROR(ESRCH)); } error = dmu_snapshot_list_next(os, - sizeof (zc->zc_name) - strlen(zc->zc_name), - zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie, + sizeof (zl->zl_name) - strlen(zl->zl_name), + zl->zl_name + strlen(zl->zl_name), &zl->zl_obj, &zl->zl_cookie, NULL); - if (error == 0 && !zc->zc_simple) { + if (error == 0 && !simple) { dsl_dataset_t *ds; dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool; - error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds); + error = dsl_dataset_hold_obj(dp, zl->zl_obj, FTAG, &ds); if (error == 0) { objset_t *ossnap; + nvlist_t *nv; error = dmu_objset_from_ds(ds, &ossnap); - if (error == 0) - error = zfs_ioc_objset_stats_impl(zc, ossnap); + if (error == 0) { + error = zfs_ioc_objset_stats_impl_nohold(&nv, + zl->zl_objset_stats, ossnap, B_FALSE); + } dsl_dataset_rele(ds, FTAG); + if (error) + nvlist_free(nv); + else + zl->zl_nvlist = nv; + } } else if (error == ENOENT) { error = SET_ERROR(ESRCH); @@ -2279,10 +2328,77 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) dmu_objset_rele(os, FTAG); /* if we failed, undo the @ that we tacked on to zc_name */ if (error != 0) - *strchr(zc->zc_name, '@') = '\0'; + *strchr(zl->zl_name, '@') = '\0'; return (error); } +static int +zfs_ioc_list_next(zfs_cmd_t *zc, boolean_t snapshot) +{ + zfs_list_t zl; + int error; + + zl.zl_name = zc->zc_name; + zl.zl_objset_stats = &zc->zc_objset_stats; + zl.zl_cookie = zc->zc_cookie; + + if (snapshot) { + zl.zl_obj = zc->zc_obj; + error = zfs_ioc_snapshot_list_next_impl(&zl, zc->zc_simple); + } else { + error = zfs_ioc_dataset_list_next_impl(&zl); + } + + if (error == 0) { + ASSERT(zl.zl_nvlist); + zc->zc_cookie = zl.zl_cookie; + if (snapshot) + zc->zc_obj = zl.zl_obj; + error = put_nvlist(zc, zl.zl_nvlist); + nvlist_free(zl.zl_nvlist); + } + + return (error); +} + +/* + * inputs: + * zc_name name of filesystem + * zc_cookie zap cursor + * zc_nvlist_dst_size size of buffer for property nvlist + * + * outputs: + * zc_name name of next filesystem + * zc_cookie zap cursor + * zc_objset_stats stats + * zc_nvlist_dst property nvlist + * zc_nvlist_dst_size size of property nvlist + */ +static int +zfs_ioc_dataset_list_next(zfs_cmd_t *zc) +{ + return (zfs_ioc_list_next(zc, B_FALSE)); +} + + +/* + * inputs: + * zc_name name of filesystem + * zc_cookie zap cursor + * zc_nvlist_dst_size size of buffer for property nvlist + * + * outputs: + * zc_name name of next snapshot + * zc_objset_stats stats + * zc_nvlist_dst property nvlist + * zc_nvlist_dst_size size of property nvlist + */ +static int +zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) +{ + return (zfs_ioc_list_next(zc, B_TRUE)); +} + static int zfs_prop_set_userquota(const char *dsname, nvpair_t *pair) { From 43037a4c5a4e8ecb1284e526a11c1faec7c34351 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Wed, 5 Nov 2014 12:59:02 -0500 Subject: [PATCH 10/40] Pass index property values as strings Switch the ioctl interface to passing index properties as strings rather than integers so that future extensions are independent of the value used in the ioctl interface. We retain the ability to pass index values for backward compatibility with older tools, but this functionality is depreciated. Signed-off-by: Richard Yao --- lib/libzfs/libzfs_dataset.c | 8 +++++++- lib/libzfs/libzfs_util.c | 2 ++ module/zfs/dsl_prop.c | 26 +++++++++++++++----------- module/zfs/spa.c | 36 ++++++++++++++++++++++++++++++++++-- module/zfs/zfs_ioctl.c | 37 +++++++++++++++++++++++++++++++++---- 5 files changed, 91 insertions(+), 18 deletions(-) diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 088ee35c4f6b..f416ac6729b4 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1762,11 +1762,17 @@ getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) { nvlist_t *nv; uint64_t value; + char *strval = NULL; *source = NULL; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(prop), &nv) == 0) { - verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); + if ((zfs_prop_get_type(prop) == PROP_TYPE_INDEX) && + nvlist_lookup_string(nv, ZPROP_VALUE, &strval) == 0) { + zprop_string_to_index(prop, strval, &value, + ZFS_TYPE_DATASET); + } else + VERIFY0(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value)); (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); } else { verify(!zhp->zfs_props_table || diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 678eeadc0414..2ea2d99dadf7 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -1581,6 +1581,8 @@ zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop, zprop_values(prop, type)); goto error; } + *ivalp = 0; + *svalp = value; break; default: diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index cc7b80a4a4ab..0188decec52d 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -773,9 +773,10 @@ dsl_props_set_special_check(dsl_dataset_t *ds, zprop_source_t source, case DATA_TYPE_STRING: if (nvpair_value_string(pair, &strval) != 0) return (SET_ERROR(EINVAL)); - if (zfs_prop_get_type(prop) == PROP_TYPE_INDEX && - zfs_prop_string_to_index(prop, strval, &intval) != 0) - return (SET_ERROR(EINVAL)); + if (!zfs_prop_user(propname) && + zfs_prop_get_type(prop) == PROP_TYPE_INDEX && + zfs_prop_string_to_index(prop, strval, &intval) != 0) + return (SET_ERROR(EINVAL)); break; case DATA_TYPE_UINT64: VERIFY(0 == nvpair_value_uint64(pair, &intval)); @@ -788,14 +789,16 @@ dsl_props_set_special_check(dsl_dataset_t *ds, zprop_source_t source, err = dsl_dir_set_quota_check_impl(ds, source, intval, tx); break; case ZFS_PROP_REFQUOTA: - err = dsl_dataset_set_refquota_check_impl(ds, source, intval, tx); + err = dsl_dataset_set_refquota_check_impl(ds, source, intval, + tx); break; case ZFS_PROP_RESERVATION: - err = dsl_dir_set_reservation_check_impl(ds, source, intval, tx); + err = dsl_dir_set_reservation_check_impl(ds, source, intval, + tx); break; case ZFS_PROP_REFRESERVATION: - err = dsl_dataset_set_refreservation_check_impl(ds, source, intval, - tx); + err = dsl_dataset_set_refreservation_check_impl(ds, source, + intval, tx); break; case ZFS_PROP_VOLSIZE: case ZFS_PROP_SNAPDEV: @@ -822,9 +825,9 @@ dsl_props_set_special_sync(dsl_dataset_t *ds, zprop_source_t source, if (nvpair_value_string(pair, &strval) != 0) return (SET_ERROR(EINVAL)); if (!zfs_prop_user(propname) && - zfs_prop_get_type(prop) == PROP_TYPE_INDEX && - zfs_prop_string_to_index(prop, strval, &intval) != 0) - return (SET_ERROR(EINVAL)); + zfs_prop_get_type(prop) == PROP_TYPE_INDEX && + zfs_prop_string_to_index(prop, strval, &intval) != 0) + return (SET_ERROR(EINVAL)); break; case DATA_TYPE_UINT64: VERIFY0(nvpair_value_uint64(pair, &intval)); @@ -844,7 +847,8 @@ dsl_props_set_special_sync(dsl_dataset_t *ds, zprop_source_t source, dsl_dir_set_reservation_sync_impl(ds, source, intval, tx); break; case ZFS_PROP_REFRESERVATION: - dsl_dataset_set_refreservation_sync_impl(ds, source, intval, tx); + dsl_dataset_set_refreservation_sync_impl(ds, source, intval, + tx); break; case ZFS_PROP_VOLSIZE: case ZFS_PROP_SNAPDEV: diff --git a/module/zfs/spa.c b/module/zfs/spa.c index fe266a5b2969..07a48c13a0ac 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -460,6 +460,14 @@ spa_prop_validate(spa_t *spa, nvlist_t *props) case ZPOOL_PROP_AUTOREPLACE: case ZPOOL_PROP_LISTSNAPS: case ZPOOL_PROP_AUTOEXPAND: + error = nvpair_value_string(elem, &strval); + if (error == 0) { + error = zpool_prop_string_to_index(prop, + strval, &intval); + if (!error && intval > 1) + error = SET_ERROR(EINVAL); + break; + } error = nvpair_value_uint64(elem, &intval); if (!error && intval > 1) error = SET_ERROR(EINVAL); @@ -4043,6 +4051,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags) int error; nvlist_t *nvroot; nvlist_t **spares, **l2cache; + nvpair_t *elem; uint_t nspares, nl2cache; /* @@ -4059,8 +4068,24 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags) */ (void) nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot); - (void) nvlist_lookup_uint64(props, - zpool_prop_to_name(ZPOOL_PROP_READONLY), &readonly); + + error = nvlist_lookup_nvpair(props, + zpool_prop_to_name(ZPOOL_PROP_READONLY), &elem); + if (error == 0) { + switch (nvpair_type(elem)) { + case DATA_TYPE_STRING: + error = zpool_prop_string_to_index(ZPOOL_PROP_READONLY, + fnvpair_value_string(elem), &readonly); + break; + case DATA_TYPE_UINT64: + readonly = fnvpair_value_uint64(elem); + break; + /* XXX: Silently ignore to match legacy behavior. */ + default: + break; + } + } + if (readonly) mode = FREAD; spa = spa_add(pool, config, altroot); @@ -6204,6 +6229,12 @@ spa_sync_props(void *arg, dmu_tx_t *tx) proptype = zpool_prop_get_type(prop); if (nvpair_type(elem) == DATA_TYPE_STRING) { + if (proptype == PROP_TYPE_INDEX) { + strval = fnvpair_value_string(elem); + VERIFY0(zpool_prop_string_to_index(prop, + strval, &intval)); + goto setint; + } ASSERT(proptype == PROP_TYPE_STRING); strval = fnvpair_value_string(elem); VERIFY0(zap_update(mos, @@ -6219,6 +6250,7 @@ spa_sync_props(void *arg, dmu_tx_t *tx) VERIFY0(zpool_prop_index_to_string( prop, intval, &unused)); } +setint: VERIFY0(zap_update(mos, spa->spa_pool_props_object, propname, 8, 1, &intval, tx)); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index f721e45d72e4..9a51256baf99 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2477,7 +2477,15 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) return (-1); - VERIFY(0 == nvpair_value_uint64(pair, &intval)); + if (((nvpair_type(pair) == DATA_TYPE_STRING) && + (zfs_prop_get_type(prop) == PROP_TYPE_INDEX))) { + char *strval; + if (nvpair_value_string(pair, &strval) != 0) + return (-1); + if (zfs_prop_string_to_index(prop, strval, &intval) != 0) + return (-1); + } else + VERIFY(0 == nvpair_value_uint64(pair, &intval)); switch (prop) { case ZFS_PROP_FILESYSTEM_LIMIT: @@ -2581,8 +2589,19 @@ zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, } } else if (err == 0) { if (nvpair_type(propval) == DATA_TYPE_STRING) { - if (zfs_prop_get_type(prop) != PROP_TYPE_STRING) + switch (zfs_prop_get_type(prop)) { + case PROP_TYPE_INDEX: + strval = fnvpair_value_string(propval); + if (zfs_prop_string_to_index(prop, + strval, &intval) != 0) + err = SET_ERROR(EINVAL); + break; + case PROP_TYPE_STRING: + break; + default: err = SET_ERROR(EINVAL); + break; + } } else if (nvpair_type(propval) == DATA_TYPE_UINT64) { const char *unused; @@ -2613,20 +2632,30 @@ zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, err = zfs_check_settable(dsname, pair, CRED()); if (err == 0) { + nvlist_t *tnvl = NULL; err = zfs_prop_set_special(dsname, source, pair); if (err == -1) { /* * For better performance we build up a list of * properties to set in a single transaction. */ - err = nvlist_add_nvpair(genericnvl, pair); + tnvl = genericnvl; } else if (err != 0 && nvl != retrynvl) { /* * This may be a spurious error caused by * receiving quota and reservation out of order. * Try again in a second pass. */ - err = nvlist_add_nvpair(retrynvl, pair); + tnvl = retrynvl; + } + if (tnvl) { + if (nvpair_type(propval) == DATA_TYPE_STRING && + !zfs_prop_user(propname) && + zfs_prop_get_type(prop) == PROP_TYPE_INDEX) + err = nvlist_add_uint64(tnvl, propname, + intval); + else + err = nvlist_add_nvpair(tnvl, pair); } } From 26fe94421b8ed217d15035562fbe119af1897ac4 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 24 Nov 2014 04:28:09 -0500 Subject: [PATCH 11/40] Implement kernel side of stable ioctl interface Signed-off-by: Richard Yao --- include/sys/fs/zfs.h | 5 + module/zfs/zfs_ioctl.c | 458 +++++++++++++++++++++++++++++++++++------ 2 files changed, 405 insertions(+), 58 deletions(-) diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 4da144c724ab..72013824eea8 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -898,6 +898,11 @@ typedef enum zfs_ioc { */ ZFS_IOC_FREEBSD = ('Z' << 8) + 0xC0, + /* + * OpenZFS - 1/64 numbers reserved. + */ + ZFS_IOC_OPENZFS = ('Z' << 8) + 0x100, + ZFS_IOC_LIBZFS_CORE, ZFS_IOC_LAST } zfs_ioc_t; diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 9a51256baf99..213ae03b5935 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -30,6 +30,7 @@ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2015, ClusterHQ, Inc. All rights reserved. */ /* @@ -204,7 +205,9 @@ static uint_t zfs_allow_log_key; typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *); typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *); -typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *); +typedef int zfs_ioc_stable_func_t(const char *, nvlist_t *, nvlist_t *, + nvlist_t *, uint64_t); +typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, nvlist_t *, cred_t *); typedef enum { NO_NAME, @@ -229,6 +232,16 @@ typedef struct zfs_ioc_vec { const char *zvec_name; } zfs_ioc_vec_t; +typedef struct zfs_stable_ioc_vec { + zfs_ioc_stable_func_t *zvec_func; + zfs_secpolicy_func_t *zvec_secpolicy; + zfs_ioc_namecheck_t zvec_namecheck; + boolean_t zvec_allow_log; + zfs_ioc_poolcheck_t zvec_pool_check; + boolean_t zvec_smush_outnvlist; + const char *const zvec_name; +} zfs_stable_ioc_vec_t; + /* This array is indexed by zfs_userquota_prop_t */ static const char *userquota_perms[] = { ZFS_DELEG_PERM_USERUSED, @@ -355,7 +368,7 @@ zfs_log_history(zfs_cmd_t *zc) */ /* ARGSUSED */ static int -zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { return (0); } @@ -366,7 +379,7 @@ zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { if (INGLOBALZONE(curproc) || zone_dataset_visible(zc->zc_name, NULL)) @@ -629,7 +642,8 @@ zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval, /* ARGSUSED */ static int -zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { int error; @@ -646,7 +660,8 @@ zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { return (zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_ROLLBACK, cr)); @@ -654,7 +669,7 @@ zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { dsl_pool_t *dp; dsl_dataset_t *ds; @@ -690,7 +705,8 @@ zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { return (zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_SEND, cr)); @@ -699,7 +715,8 @@ zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) #ifdef HAVE_SMB_SHARE /* ARGSUSED */ static int -zfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { vnode_t *vp; int error; @@ -724,7 +741,7 @@ zfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) #endif /* HAVE_SMB_SHARE */ int -zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { #ifdef HAVE_SMB_SHARE if (!INGLOBALZONE(curproc)) @@ -741,7 +758,8 @@ zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) } int -zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { #ifdef HAVE_SMB_SHARE if (!INGLOBALZONE(curproc)) @@ -793,7 +811,8 @@ zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); } @@ -804,7 +823,8 @@ zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { nvlist_t *snaps; nvpair_t *pair, *nextpair; @@ -866,14 +886,15 @@ zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); } /* ARGSUSED */ static int -zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { dsl_pool_t *dp; dsl_dataset_t *clone; @@ -921,7 +942,7 @@ zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { int error; @@ -949,7 +970,8 @@ zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { nvlist_t *snaps; int error = 0; @@ -980,7 +1002,8 @@ zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { int error = 0; nvpair_t *pair; @@ -1006,7 +1029,8 @@ zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { nvpair_t *pair, *nextpair; int error = 0; @@ -1047,7 +1071,8 @@ zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { /* * Even root must have a proper TSD so that we know what pool @@ -1059,7 +1084,8 @@ zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) } static int -zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { char parentname[MAXNAMELEN]; int error; @@ -1088,7 +1114,7 @@ zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { if (secpolicy_sys_config(cr, B_FALSE) != 0) return (SET_ERROR(EPERM)); @@ -1101,7 +1127,7 @@ zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { int error; @@ -1117,14 +1143,15 @@ zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) */ /* ARGSUSED */ static int -zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { return (secpolicy_zinject(cr)); } /* ARGSUSED */ static int -zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); @@ -1140,9 +1167,10 @@ zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) } static int -zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { - int err = zfs_secpolicy_read(zc, innvl, cr); + int err = zfs_secpolicy_read(zc, innvl, opts, cr); if (err) return (err); @@ -1169,9 +1197,10 @@ zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) } static int -zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { - int err = zfs_secpolicy_read(zc, innvl, cr); + int err = zfs_secpolicy_read(zc, innvl, opts, cr); if (err) return (err); @@ -1184,7 +1213,8 @@ zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION, NULL, cr)); @@ -1192,7 +1222,7 @@ zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) { nvpair_t *pair; nvlist_t *holds; @@ -1218,7 +1248,8 @@ zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { nvpair_t *pair; int error; @@ -1241,7 +1272,8 @@ zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) * Policy for allowing temporary snapshots to be taken or released */ static int -zfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) +zfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { /* * A temporary snapshot is the same as a snapshot, @@ -1256,11 +1288,11 @@ zfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) error = zfs_secpolicy_snapshot_perms(zc->zc_name, cr); if (error == 0) - error = zfs_secpolicy_hold(zc, innvl, cr); + error = zfs_secpolicy_hold(zc, innvl, NULL, cr); if (error == 0) - error = zfs_secpolicy_release(zc, innvl, cr); + error = zfs_secpolicy_release(zc, innvl, NULL, cr); if (error == 0) - error = zfs_secpolicy_destroy(zc, innvl, cr); + error = zfs_secpolicy_destroy(zc, innvl, NULL, cr); return (error); } @@ -4001,7 +4033,8 @@ zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) (void) strcpy(zc->zc_value, nvpair_name(pair)); if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 || - (err = zfs_secpolicy_inherit_prop(zc, NULL, CRED())) != 0) { + (err = zfs_secpolicy_inherit_prop(zc, NULL, NULL, CRED())) + != 0) { VERIFY(nvlist_remove_nvpair(props, pair) == 0); VERIFY(nvlist_add_int32(errors, zc->zc_value, err) == 0); @@ -5414,6 +5447,332 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) return (error); } +int +pool_status_check(const char *name, zfs_ioc_namecheck_t type, + zfs_ioc_poolcheck_t check); + +#define LIBZFS_CORE_WRAPPER_FUNC_2NAME(oldname, newname) \ +static int \ +zfs_stable_ioc_zfs_##newname(const char *fsname, nvlist_t *innvl, \ + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) { \ + return (zfs_ioc_##oldname(fsname, innvl, outnvl)); \ +} + +#define LIBZFS_CORE_WRAPPER_FUNC(name) \ +LIBZFS_CORE_WRAPPER_FUNC_2NAME(name, name) + +LIBZFS_CORE_WRAPPER_FUNC(snapshot) +LIBZFS_CORE_WRAPPER_FUNC(log_history) +LIBZFS_CORE_WRAPPER_FUNC(space_snaps) +LIBZFS_CORE_WRAPPER_FUNC_2NAME(send_new, send) +LIBZFS_CORE_WRAPPER_FUNC(send_space) +LIBZFS_CORE_WRAPPER_FUNC(create) +LIBZFS_CORE_WRAPPER_FUNC(clone) +LIBZFS_CORE_WRAPPER_FUNC(destroy_snaps) +LIBZFS_CORE_WRAPPER_FUNC(hold) +LIBZFS_CORE_WRAPPER_FUNC(release) +LIBZFS_CORE_WRAPPER_FUNC(get_holds) +LIBZFS_CORE_WRAPPER_FUNC(rollback) +LIBZFS_CORE_WRAPPER_FUNC(bookmark) +LIBZFS_CORE_WRAPPER_FUNC(get_bookmarks) +LIBZFS_CORE_WRAPPER_FUNC(destroy_bookmarks) + +/* + * ioctl table for stable interface. + * Functions use zfs_/zpool_ prefixes to distinguish between their uses + * XXX: Sort entries and implement binary search. + */ +static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { +{ .zvec_name = "zfs_snapshot", + .zvec_func = zfs_stable_ioc_zfs_snapshot, + .zvec_secpolicy = zfs_secpolicy_snapshot, + .zvec_namecheck = POOL_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_log_history", + .zvec_func = zfs_stable_ioc_zfs_log_history, + .zvec_secpolicy = zfs_secpolicy_log_history, + .zvec_namecheck = NO_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, +{ .zvec_name = "zfs_space_snaps", + .zvec_func = zfs_stable_ioc_zfs_space_snaps, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, +{ .zvec_name = "zfs_send", + .zvec_func = zfs_stable_ioc_zfs_send, + .zvec_secpolicy = zfs_secpolicy_send_new, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, +{ .zvec_name = "zfs_send_space", + .zvec_func = zfs_stable_ioc_zfs_send_space, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, +{ .zvec_name = "zfs_create", + .zvec_func = zfs_stable_ioc_zfs_create, + .zvec_secpolicy = zfs_secpolicy_config, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_clone", + .zvec_func = zfs_stable_ioc_zfs_clone, + .zvec_secpolicy = zfs_secpolicy_create_clone, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_destroy_snaps", + .zvec_func = zfs_stable_ioc_zfs_destroy_snaps, + .zvec_secpolicy = zfs_secpolicy_destroy_snaps, + .zvec_namecheck = POOL_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_hold", + .zvec_func = zfs_stable_ioc_zfs_hold, + .zvec_secpolicy = zfs_secpolicy_hold, + .zvec_namecheck = POOL_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_release", + .zvec_func = zfs_stable_ioc_zfs_release, + .zvec_secpolicy = zfs_secpolicy_release, + .zvec_namecheck = POOL_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_get_holds", + .zvec_func = zfs_stable_ioc_zfs_get_holds, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, +{ .zvec_name = "zfs_rollback", + .zvec_func = zfs_stable_ioc_zfs_rollback, + .zvec_secpolicy = zfs_secpolicy_rollback, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_bookmark", + .zvec_func = zfs_stable_ioc_zfs_bookmark, + .zvec_secpolicy = zfs_secpolicy_bookmark, + .zvec_namecheck = POOL_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +{ .zvec_name = "zfs_get_bookmarks", + .zvec_func = zfs_stable_ioc_zfs_get_bookmarks, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, +{ .zvec_name = "zfs_destroy_bookmarks", + .zvec_func = zfs_stable_ioc_zfs_destroy_bookmarks, + .zvec_secpolicy = zfs_secpolicy_destroy_bookmarks, + .zvec_namecheck = POOL_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, +}; + +static const ssize_t zfs_stable_ioc_vec_count = + sizeof (zfs_stable_ioc_vec) / sizeof (zfs_stable_ioc_vec_t); + +/* Helper function to validate names */ +static inline int +zfs_namecheck(const char *name, zfs_ioc_namecheck_t namecheck, + zfs_ioc_poolcheck_t pool_check) { + int error = 0; + + switch (namecheck) { + case POOL_NAME: + if (pool_namecheck(name, NULL, NULL) != 0) + error = SET_ERROR(EINVAL); + else + error = pool_status_check(name, + namecheck, pool_check); + break; + + case DATASET_NAME: + if (dataset_namecheck(name, NULL, NULL) != 0) + error = SET_ERROR(EINVAL); + else + error = pool_status_check(name, + namecheck, pool_check); + break; + + case NO_NAME: + break; + } + + return (error); +} + +/* + * Stable API + * We use an XDR-encoded nvlist for input, which is encapsulated inside the + * legacy zfs_cmd_t. + * + * The format is: + * + * zc->zc_name -> dataset/pool name + * zc->zc_nvlist_src: { + * "cmd" -> command name (string) + * "version" -> command version (uint64) + * "opts" -> command specific options (nvlist) + * "innvl" -> command specific input data + * } + * + * Malformed XDR-encoded nvlists will result in get_nvlist() returning an error + * from nvlist_unpack(), which fails early. Consequently, all strings can be + * safely assumed to be NULL terminated. + * + * Names of commands focused on the DSL are prefixed with "zfs_" while names of + * commands focused on the SPA are prefixed with "zpool_". + * + * XXX: Unit tests are necessary, especially for malformed XDR-encoded nvlist + * inputs. + */ +static int +zfs_ioc_stable(zfs_cmd_t *zc) +{ + const char *name = zc->zc_name; + char *cmd; + nvlist_t *mnvl, *innvl, *outnvl, *opts; + uint64_t version; + int error = 0; + ssize_t i; + + zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; + + if (zc->zc_nvlist_src_size != 0) { + error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, + zc->zc_iflags, &mnvl); + if (error != 0) + goto out; + } + + if ((error = nvlist_lookup_string(mnvl, "cmd", &cmd)) != 0) + return (error); + + if (nvlist_lookup_nvlist(mnvl, "innvl", &innvl) != 0) + innvl = NULL; + + if (nvlist_lookup_nvlist(mnvl, "opts", &opts) != 0) + opts = NULL; + + if ((error = nvlist_lookup_uint64(mnvl, "version", &version)) != 0) + return (error); + + /* We do not support sequence numbers above 0 right now */ + if (version != 0) + return (EINVAL); + /* + * Ensure that all pool/dataset names are valid before we pass down to + * the lower layers. + */ + zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; + + for (i = 0; i < zfs_stable_ioc_vec_count; i++) { + if (strcmp(zfs_stable_ioc_vec[i].zvec_name, cmd) == 0) { + nvlist_t *lognv = NULL; + const zfs_stable_ioc_vec_t *vec = + &zfs_stable_ioc_vec[i]; + nvlist_t *lognv = NULL; + spa_t *spa; + int puterror = 0; + + error = zfs_namecheck(name, vec->zvec_namecheck, + vec->zvec_pool_check); + + if (error == 0 && (zc->zc_iflags & FKIOCTL)) + error = vec->zvec_secpolicy(zc, + innvl, opts, CRED()); + + if (error) + return (error); + + ASSERT(vec->zvec_func); + VERIFY0(nvlist_alloc(&outnvl, NV_UNIQUE_NAME, + KM_PUSHPAGE)); + + /* XXX: Do we want to log the mnvl as the input nvl? */ + if (vec->zvec_allow_log) { + lognv = fnvlist_alloc(); + fnvlist_add_string(lognv, ZPOOL_HIST_IOCTL, + "stable"); + fnvlist_add_nvlist(lognv, ZPOOL_HIST_INPUT_NVL, + mnvl); + } + + error = vec->zvec_func(name, innvl, outnvl, opts, + version); + if (error == 0 && vec->zvec_allow_log && + spa_open(zc->zc_name, &spa, FTAG) == 0) { + if (!nvlist_empty(outnvl)) { + fnvlist_add_nvlist(lognv, + ZPOOL_HIST_OUTPUT_NVL, outnvl); + } + (void) spa_history_log_nvl(spa, lognv); + spa_close(spa, FTAG); + } + fnvlist_free(lognv); + + if (!nvlist_empty(outnvl) || + zc->zc_nvlist_dst_size != 0) { + int smusherror = 0; + if (vec->zvec_smush_outnvlist) { + smusherror = nvlist_smush(outnvl, + zc->zc_nvlist_dst_size); + } + if (smusherror == 0) + puterror = put_nvlist(zc, outnvl); + } + + if (puterror != 0) + error = puterror; + + nvlist_free(outnvl); + break; + + } + } + +out: + nvlist_free(mnvl); + return (error); +} + static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST]; static void @@ -5583,6 +5942,8 @@ zfs_ioctl_init(void) POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); /* IOCTLS that use the legacy function signature */ + zfs_ioctl_register_legacy(ZFS_IOC_LIBZFS_CORE, zfs_ioc_stable, + zfs_secpolicy_none, NO_NAME, B_FALSE, POOL_CHECK_NONE); zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_READONLY); @@ -5971,30 +6332,11 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg) * the lower layers. */ zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; - switch (vec->zvec_namecheck) { - case POOL_NAME: - if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) - error = SET_ERROR(EINVAL); - else - error = pool_status_check(zc->zc_name, - vec->zvec_namecheck, vec->zvec_pool_check); - break; - - case DATASET_NAME: - if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) - error = SET_ERROR(EINVAL); - else - error = pool_status_check(zc->zc_name, - vec->zvec_namecheck, vec->zvec_pool_check); - break; - - case NO_NAME: - break; - } - + error = zfs_namecheck(zc->zc_name, vec->zvec_namecheck, + vec->zvec_pool_check); if (error == 0 && !(flag & FKIOCTL)) - error = vec->zvec_secpolicy(zc, innvl, CRED()); + error = vec->zvec_secpolicy(zc, innvl, NULL, CRED()); if (error != 0) goto out; From d5ddac6304f303d7e1b3746df2d1d8b38d375be3 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 23 Sep 2015 13:27:38 +0300 Subject: [PATCH 12/40] zfs_ioc_stable: call put_nvlist if outnvl is not empty *and* expected Previously put_nvlist() could be called even if zc_nvlist_dst_size was zero. --- module/zfs/zfs_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 213ae03b5935..9f9627eefcf0 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5748,7 +5748,7 @@ zfs_ioc_stable(zfs_cmd_t *zc) } fnvlist_free(lognv); - if (!nvlist_empty(outnvl) || + if (!nvlist_empty(outnvl) && zc->zc_nvlist_dst_size != 0) { int smusherror = 0; if (vec->zvec_smush_outnvlist) { From 3b5094d2431fa4b5e0ca04aa3a0342e28c560aac Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 30 Sep 2015 14:38:50 +0300 Subject: [PATCH 13/40] zfs_ioc_stable: fix inverted FKIOCTL check That bug resulted in zvec_secpolicy() checks not being run. --- module/zfs/zfs_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 9f9627eefcf0..4c36d3c4fdc1 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5715,7 +5715,7 @@ zfs_ioc_stable(zfs_cmd_t *zc) error = zfs_namecheck(name, vec->zvec_namecheck, vec->zvec_pool_check); - if (error == 0 && (zc->zc_iflags & FKIOCTL)) + if (error == 0 && !(zc->zc_iflags & FKIOCTL)) error = vec->zvec_secpolicy(zc, innvl, opts, CRED()); From 7baf4cc6aa4ed1d65f6e230b11862d66285b61a1 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 23 Sep 2015 13:24:10 +0300 Subject: [PATCH 14/40] put_nvlist: set zc_nvlist_dst_filled only on success --- module/zfs/zfs_ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 4c36d3c4fdc1..6dc8b19fba26 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -1390,7 +1390,8 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) } zc->zc_nvlist_dst_size = size; - zc->zc_nvlist_dst_filled = B_TRUE; + if (error == 0) + zc->zc_nvlist_dst_filled = B_TRUE; return (error); } From 22b8923a119218b65dd358fe6f96c21ed9aa7ac0 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 25 Nov 2014 06:19:20 -0500 Subject: [PATCH 15/40] Make libzfs_core hook into stable API Signed-off-by: Richard Yao --- lib/libzfs_core/libzfs_core.c | 55 +++++++++++++++++++++++++---------- module/zfs/zfs_ioctl.c | 9 ------ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 5da9cda9541c..78fb509bd9a0 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. + * Copyright (c) 2015 ClusterHQ. All rights reserved. */ /* @@ -116,7 +117,7 @@ libzfs_core_fini(void) } static int -lzc_ioctl(zfs_ioc_t ioc, const char *name, +lzc_ioctl_impl(zfs_ioc_t ioc, const char *name, nvlist_t *source, nvlist_t **resultp) { zfs_cmd_t zc = {"\0"}; @@ -169,6 +170,29 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name, return (error); } +static int +lzc_ioctl(const char *cmd, const char *name, nvlist_t *source, + nvlist_t *opts, nvlist_t **resultp, uint64_t version) +{ + nvlist_t *args = fnvlist_alloc(); + int error; + + ASSERT(*cmd); + + fnvlist_add_string(args, "cmd", cmd); + if (source) + fnvlist_add_nvlist(args, "innvl", source); + if (opts) + fnvlist_add_nvlist(args, "opts", opts); + fnvlist_add_uint64(args, "version", version); + + error = lzc_ioctl_impl(ZFS_IOC_LIBZFS_CORE, name, args, resultp); + + fnvlist_free(args); + + return (error); +} + int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props) { @@ -177,7 +201,7 @@ lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props) fnvlist_add_int32(args, "type", type); if (props != NULL) fnvlist_add_nvlist(args, "props", props); - error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL); + error = lzc_ioctl("zfs_create", fsname, args, NULL, NULL, 0); nvlist_free(args); return (error); } @@ -191,7 +215,7 @@ lzc_clone(const char *fsname, const char *origin, fnvlist_add_string(args, "origin", origin); if (props != NULL) fnvlist_add_nvlist(args, "props", props); - error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL); + error = lzc_ioctl("zfs_clone", fsname, args, NULL, NULL, 0); nvlist_free(args); return (error); } @@ -233,7 +257,7 @@ lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist) if (props != NULL) fnvlist_add_nvlist(args, "props", props); - error = lzc_ioctl(ZFS_IOC_SNAPSHOT, pool, args, errlist); + error = lzc_ioctl("zfs_snapshot", pool, args, NULL, errlist, 0); nvlist_free(args); return (error); @@ -283,7 +307,7 @@ lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist) if (defer) fnvlist_add_boolean(args, "defer"); - error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist); + error = lzc_ioctl("zfs_destroy_snaps", pool, args, NULL, errlist, 0); nvlist_free(args); return (error); @@ -309,7 +333,7 @@ lzc_snaprange_space(const char *firstsnap, const char *lastsnap, args = fnvlist_alloc(); fnvlist_add_string(args, "firstsnap", firstsnap); - err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result); + err = lzc_ioctl("zfs_space_snaps", lastsnap, args, NULL, &result, 0); nvlist_free(args); if (err == 0 && usedp != NULL) *usedp = fnvlist_lookup_uint64(result, "used"); @@ -378,7 +402,7 @@ lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist) if (cleanup_fd != -1) fnvlist_add_int32(args, "cleanup_fd", cleanup_fd); - error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist); + error = lzc_ioctl("zfs_hold", pool, args, NULL, errlist, 0); nvlist_free(args); return (error); } @@ -418,7 +442,7 @@ lzc_release(nvlist_t *holds, nvlist_t **errlist) (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); pool[strcspn(pool, "/@")] = '\0'; - return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist)); + return (lzc_ioctl("zfs_release", pool, holds, NULL, errlist, 0)); } /* @@ -433,7 +457,7 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp) { int error; nvlist_t *innvl = fnvlist_alloc(); - error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp); + error = lzc_ioctl("zfs_get_holds", snapname, innvl, NULL, holdsp, 0); fnvlist_free(innvl); return (error); } @@ -479,7 +503,7 @@ lzc_send(const char *snapname, const char *from, int fd, fnvlist_add_boolean(args, "largeblockok"); if (flags & LZC_SEND_FLAG_EMBED_DATA) fnvlist_add_boolean(args, "embedok"); - err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL); + err = lzc_ioctl("zfs_send", snapname, args, NULL, NULL, 0); nvlist_free(args); return (err); } @@ -509,7 +533,7 @@ lzc_send_space(const char *snapname, const char *from, uint64_t *spacep) args = fnvlist_alloc(); if (from != NULL) fnvlist_add_string(args, "from", from); - err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result); + err = lzc_ioctl("zfs_send_space", snapname, args, NULL, &result, 0); nvlist_free(args); if (err == 0) *spacep = fnvlist_lookup_uint64(result, "space"); @@ -637,7 +661,7 @@ lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen) int err; args = fnvlist_alloc(); - err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result); + err = lzc_ioctl("zfs_rollback", fsname, args, NULL, &result, 0); nvlist_free(args); if (err == 0 && snapnamebuf != NULL) { const char *snapname = fnvlist_lookup_string(result, "target"); @@ -673,7 +697,7 @@ lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist) (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); pool[strcspn(pool, "/#")] = '\0'; - error = lzc_ioctl(ZFS_IOC_BOOKMARK, pool, bookmarks, errlist); + error = lzc_ioctl("zfs_bookmark", pool, bookmarks, NULL, errlist, 0); return (error); } @@ -702,7 +726,7 @@ lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist) int lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks) { - return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks)); + return (lzc_ioctl_impl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks)); } /* @@ -735,7 +759,8 @@ lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist) (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); pool[strcspn(pool, "/#")] = '\0'; - error = lzc_ioctl(ZFS_IOC_DESTROY_BOOKMARKS, pool, bmarks, errlist); + error = lzc_ioctl("zfs_destroy_bookmarks", pool, bmarks, NULL, errlist, + 0); return (error); } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 6dc8b19fba26..d721100dc26b 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5475,7 +5475,6 @@ LIBZFS_CORE_WRAPPER_FUNC(release) LIBZFS_CORE_WRAPPER_FUNC(get_holds) LIBZFS_CORE_WRAPPER_FUNC(rollback) LIBZFS_CORE_WRAPPER_FUNC(bookmark) -LIBZFS_CORE_WRAPPER_FUNC(get_bookmarks) LIBZFS_CORE_WRAPPER_FUNC(destroy_bookmarks) /* @@ -5588,14 +5587,6 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_TRUE, .zvec_allow_log = B_TRUE, }, -{ .zvec_name = "zfs_get_bookmarks", - .zvec_func = zfs_stable_ioc_zfs_get_bookmarks, - .zvec_secpolicy = zfs_secpolicy_read, - .zvec_namecheck = DATASET_NAME, - .zvec_pool_check = POOL_CHECK_SUSPENDED, - .zvec_smush_outnvlist = B_FALSE, - .zvec_allow_log = B_FALSE, -}, { .zvec_name = "zfs_destroy_bookmarks", .zvec_func = zfs_stable_ioc_zfs_destroy_bookmarks, .zvec_secpolicy = zfs_secpolicy_destroy_bookmarks, From 8a3fbe158fba415d3dfa01ef118730826e0359bf Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 26 Feb 2015 17:52:43 +0200 Subject: [PATCH 16/40] add lzc_promote --- include/libzfs_core.h | 1 + lib/libzfs_core/libzfs_core.c | 9 ++++++ module/zfs/zfs_ioctl.c | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index bdd6c951ee49..20e834964dd7 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -41,6 +41,7 @@ void libzfs_core_fini(void); int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); int lzc_create(const char *, dmu_objset_type_t, nvlist_t *); int lzc_clone(const char *, const char *, nvlist_t *); +int lzc_promote(const char *); int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); int lzc_bookmark(nvlist_t *, nvlist_t **); int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 78fb509bd9a0..3f3babf4677e 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -220,6 +220,15 @@ lzc_clone(const char *fsname, const char *origin, return (error); } +int +lzc_promote(const char *fsname) +{ + int error; + + error = lzc_ioctl("zfs_promote", fsname, NULL, NULL, NULL, 0); + return (error); +} + /* * Creates snapshots. * diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index d721100dc26b..e65f53dc1af5 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5448,6 +5448,54 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) return (error); } +static int +zfs_stable_ioc_promote(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, + nvlist_t *opts, uint64_t version) +{ + char parentname[MAXNAMELEN]; + char conflsnap[MAXNAMELEN]; + dsl_pool_t *dp; + dsl_dataset_t *clone; + dsl_dataset_t *origin = NULL; + dsl_dir_t *dd; + char *cp; + int error; + + error = dsl_pool_hold(fsname, FTAG, &dp); + if (error != 0) + return (error); + + error = dsl_dataset_hold(dp, fsname, FTAG, &clone); + if (error == 0) { + dd = clone->ds_dir; + error = dsl_dataset_hold_obj(dd->dd_pool, + dd->dd_phys->dd_origin_obj, FTAG, &origin); + if (error != 0) { + dsl_dataset_rele(clone, FTAG); + dsl_pool_rele(dp, FTAG); + return (error); + } + + dsl_dataset_name(origin, parentname); + dsl_dataset_rele(origin, FTAG); + dsl_dataset_rele(clone, FTAG); + } + dsl_pool_rele(dp, FTAG); + + /* + * We don't need to unmount *all* the origin fs's snapshots, but + * it's easier. + */ + (void) dmu_objset_find(parentname, + zfs_unmount_snap_cb, NULL, DS_FIND_SNAPSHOTS); + + error = dsl_dataset_promote(fsname, conflsnap); + if (error != 0) + fnvlist_add_string(outnvl, "conflsnap", conflsnap); + + return (error); +} + int pool_status_check(const char *name, zfs_ioc_namecheck_t type, zfs_ioc_poolcheck_t check); @@ -5539,6 +5587,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_TRUE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_promote", + .zvec_func = zfs_stable_ioc_promote, + .zvec_secpolicy = zfs_secpolicy_promote, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_TRUE, +}, { .zvec_name = "zfs_destroy_snaps", .zvec_func = zfs_stable_ioc_zfs_destroy_snaps, .zvec_secpolicy = zfs_secpolicy_destroy_snaps, From 5ee0b6923983047f0d7c093c3320fdb5477b98a2 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 11 Jul 2015 18:34:08 -0400 Subject: [PATCH 17/40] lzc_promote() should take opts nvlist_t Signed-off-by: Richard Yao --- include/libzfs_core.h | 2 +- lib/libzfs_core/libzfs_core.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 20e834964dd7..3d0362a034f8 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -41,7 +41,7 @@ void libzfs_core_fini(void); int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); int lzc_create(const char *, dmu_objset_type_t, nvlist_t *); int lzc_clone(const char *, const char *, nvlist_t *); -int lzc_promote(const char *); +int lzc_promote(const char *, nvlist_t *); int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); int lzc_bookmark(nvlist_t *, nvlist_t **); int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 3f3babf4677e..9ffbb39221c2 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -221,11 +221,11 @@ lzc_clone(const char *fsname, const char *origin, } int -lzc_promote(const char *fsname) +lzc_promote(const char *fsname, nvlist_t *opts) { int error; - error = lzc_ioctl("zfs_promote", fsname, NULL, NULL, NULL, 0); + error = lzc_ioctl("zfs_promote", fsname, NULL, opts, NULL, 0); return (error); } From 9bd91d8d1ba52bb48ed175b2490e30f4d644888c Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 15 Sep 2015 12:49:49 -0400 Subject: [PATCH 18/40] fix lzc_promote build Signed-off-by: Richard Yao --- module/zfs/zfs_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index e65f53dc1af5..6cb1c74bde5f 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5469,7 +5469,7 @@ zfs_stable_ioc_promote(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, if (error == 0) { dd = clone->ds_dir; error = dsl_dataset_hold_obj(dd->dd_pool, - dd->dd_phys->dd_origin_obj, FTAG, &origin); + dsl_dir_phys(dd)->dd_origin_obj, FTAG, &origin); if (error != 0) { dsl_dataset_rele(clone, FTAG); dsl_pool_rele(dp, FTAG); From 9e217cc04a1b8ed609954f29f6548562520f97c9 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 26 Feb 2015 17:54:09 +0200 Subject: [PATCH 19/40] add lzc_send_progress this is libzfs_core counterpart for ZFS_IOC_SEND_PROGRESS --- include/libzfs_core.h | 1 + lib/libzfs_core/libzfs_core.c | 21 +++++++++++++ module/zfs/zfs_ioctl.c | 58 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 3d0362a034f8..672b4e3b67c6 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -61,6 +61,7 @@ enum lzc_send_flags { int lzc_send(const char *, const char *, int, enum lzc_send_flags); int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int); int lzc_send_space(const char *, const char *, uint64_t *); +int lzc_send_progress(const char *, int, uint64_t *); boolean_t lzc_exists(const char *); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 9ffbb39221c2..8ee1d5395191 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -550,6 +550,27 @@ lzc_send_space(const char *snapname, const char *from, uint64_t *spacep) return (err); } +/* + * Query number of bytes written in a given send stream + * for a given snapshot thus far. + */ +int +lzc_send_progress(const char *snapname, int fd, uint64_t *bytesp) +{ + nvlist_t *args; + nvlist_t *result; + int err; + + args = fnvlist_alloc(); + fnvlist_add_int32(args, "fd", fd); + err = lzc_ioctl("zfs_send_progress", snapname, args, NULL, &result, 0); + nvlist_free(args); + if (err == 0) + *bytesp = fnvlist_lookup_uint64(result, "offset"); + nvlist_free(result); + return (err); +} + static int recv_read(int fd, void *buf, int ilen) { diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 6cb1c74bde5f..f07b43a80495 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5448,6 +5448,56 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) return (error); } +static int +zfs_stable_ioc_send_progress(const char *snapname, nvlist_t *innvl, + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) +{ + dsl_pool_t *dp; + dsl_dataset_t *ds; + dmu_sendarg_t *dsp = NULL; + int error; + int fd; + + error = nvlist_lookup_int32(innvl, "fd", &fd); + if (error != 0) + return (SET_ERROR(EINVAL)); + + error = dsl_pool_hold(snapname, FTAG, &dp); + if (error != 0) + return (error); + + error = dsl_dataset_hold(dp, snapname, FTAG, &ds); + if (error != 0) { + dsl_pool_rele(dp, FTAG); + return (error); + } + + mutex_enter(&ds->ds_sendstream_lock); + + /* + * Iterate over all the send streams currently active on this dataset. + * If there's one which matches the specified file descriptor _and_ the + * stream was started by the current process, return the progress of + * that stream. + */ + for (dsp = list_head(&ds->ds_sendstreams); dsp != NULL; + dsp = list_next(&ds->ds_sendstreams, dsp)) { + if (dsp->dsa_outfd == fd && + dsp->dsa_proc->group_leader == curproc->group_leader) + break; + } + + if (dsp != NULL) + fnvlist_add_uint64(outnvl, "offset", *(dsp->dsa_off)); + else + error = SET_ERROR(ENOENT); + + mutex_exit(&ds->ds_sendstream_lock); + dsl_dataset_rele(ds, FTAG); + dsl_pool_rele(dp, FTAG); + return (error); +} + static int zfs_stable_ioc_promote(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, nvlist_t *opts, uint64_t version) @@ -5571,6 +5621,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_FALSE, .zvec_allow_log = B_FALSE, }, +{ .zvec_name = "zfs_send_progress", + .zvec_func = zfs_stable_ioc_send_progress, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, { .zvec_name = "zfs_create", .zvec_func = zfs_stable_ioc_zfs_create, .zvec_secpolicy = zfs_secpolicy_config, From 88a43f3c1d553cdb362d6355a49e1222611164e1 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 26 Feb 2015 17:56:04 +0200 Subject: [PATCH 20/40] add lzc_set_props to set multiple properties of a single dataset --- include/libzfs_core.h | 1 + lib/libzfs_core/libzfs_core.c | 13 +++++++++++++ module/zfs/zfs_ioctl.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 672b4e3b67c6..614820f8bd93 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -42,6 +42,7 @@ int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); int lzc_create(const char *, dmu_objset_type_t, nvlist_t *); int lzc_clone(const char *, const char *, nvlist_t *); int lzc_promote(const char *, nvlist_t *); +int lzc_set_props(const char *, nvlist_t *, boolean_t); int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); int lzc_bookmark(nvlist_t *, nvlist_t **); int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 8ee1d5395191..c5648d9003fb 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -229,6 +229,19 @@ lzc_promote(const char *fsname, nvlist_t *opts) return (error); } +int +lzc_set_props(const char *fsname, nvlist_t *props, boolean_t received) +{ + int error; + nvlist_t *opts = fnvlist_alloc(); + + if (received) + fnvlist_add_boolean(opts, "received"); + error = lzc_ioctl("zfs_set_props", fsname, props, opts, NULL, 0); + nvlist_free(opts); + return (error); +} + /* * Creates snapshots. * diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index f07b43a80495..0ad708ef96ee 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5546,6 +5546,33 @@ zfs_stable_ioc_promote(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, return (error); } +static int +zfs_stable_ioc_set_props(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, + nvlist_t *opts, uint64_t version) +{ + zprop_source_t source; + boolean_t received; + int error = 0; + + received = nvlist_exists(opts, "received"); + source = (received ? ZPROP_SRC_RECEIVED : ZPROP_SRC_LOCAL); + if (received) { + nvlist_t *origprops; + + if (dsl_prop_get_received(fsname, &origprops) == 0) { + (void) clear_received_props(fsname, origprops, innvl); + nvlist_free(origprops); + } + + error = dsl_prop_set_hasrecvd(fsname); + } + + if (error == 0) + error = zfs_set_prop_nvlist(fsname, source, innvl, outnvl); + + return (error); +} + int pool_status_check(const char *name, zfs_ioc_namecheck_t type, zfs_ioc_poolcheck_t check); @@ -5653,6 +5680,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_FALSE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_set_props", + .zvec_func = zfs_stable_ioc_set_props, + .zvec_secpolicy = zfs_secpolicy_config, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, { .zvec_name = "zfs_destroy_snaps", .zvec_func = zfs_stable_ioc_zfs_destroy_snaps, .zvec_secpolicy = zfs_secpolicy_destroy_snaps, From c78f0bd8f5661bbdd75716176f78c59890f57b24 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 11 Jul 2015 17:25:37 -0400 Subject: [PATCH 21/40] Improve zfs_stable_ioc_set_props before it is stable lzc_set_props() will now expose opts nvlist, provide an errlist and support atomic operations. THe latter of those requires additional explanation. The legacy API was atomic on success and non-atomic on failure such that a best effort was made to set as many properties as possible and the stable API initially inherited this behavior. Albert Lee pointed out that this could race with zfs_list and upon review, this also conflicts with the atomicity goals for the stable API, so we change it to be atomic such that the failure to set any property on a dataset will result in the failure of all properties, rather than just one. The stable API permits aggregration of calls to set properties on multiple datasets into one and the guarentee of atomicity is only made at the dataset level, such that the failure to set properties on 1 dataset will not affect the others. It is not clear that stronger atomicity is required and the locking required to do it is expensive enough that this implementation does not attempt it. Signed-off-by: Richard Yao --- include/libzfs_core.h | 2 +- lib/libzfs_core/libzfs_core.c | 9 ++---- module/zfs/zfs_ioctl.c | 53 ++++++++++++++++++++++++----------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 614820f8bd93..bf179e6055d7 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -42,7 +42,7 @@ int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); int lzc_create(const char *, dmu_objset_type_t, nvlist_t *); int lzc_clone(const char *, const char *, nvlist_t *); int lzc_promote(const char *, nvlist_t *); -int lzc_set_props(const char *, nvlist_t *, boolean_t); +int lzc_set_props(const char *, nvlist_t *, nvlist_t *, nvlist_t **); int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); int lzc_bookmark(nvlist_t *, nvlist_t **); int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index c5648d9003fb..c474a6a94268 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -230,15 +230,12 @@ lzc_promote(const char *fsname, nvlist_t *opts) } int -lzc_set_props(const char *fsname, nvlist_t *props, boolean_t received) +lzc_set_props(const char *fsname, nvlist_t *props, nvlist_t *opts, + nvlist_t **errlist) { int error; - nvlist_t *opts = fnvlist_alloc(); - if (received) - fnvlist_add_boolean(opts, "received"); - error = lzc_ioctl("zfs_set_props", fsname, props, opts, NULL, 0); - nvlist_free(opts); + error = lzc_ioctl("zfs_set_props", fsname, props, opts, errlist, 0); return (error); } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 0ad708ef96ee..7165bd1f65ba 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -257,7 +257,8 @@ static int zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errors); static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, boolean_t *); -int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *); +int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *, + boolean_t); static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp); static void @@ -1515,7 +1516,7 @@ zfs_ioc_pool_create(zfs_cmd_t *zc) * Set the remaining root properties */ if (!error && (error = zfs_set_prop_nvlist(zc->zc_name, - ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) + ZPROP_SRC_LOCAL, rootprops, NULL, B_FALSE)) != 0) (void) spa_destroy(zc->zc_name); pool_props_bad: @@ -2581,7 +2582,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, */ int zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, - nvlist_t *errlist) + nvlist_t *errlist, boolean_t atomic) { nvpair_t *pair; nvpair_t *propval; @@ -2664,6 +2665,24 @@ zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, if (err == 0) err = zfs_check_settable(dsname, pair, CRED()); + /* + * Atomically setting old-style special properties is not + * supported. + */ + switch (prop) { + case ZFS_PROP_FILESYSTEM_LIMIT: + case ZFS_PROP_SNAPSHOT_LIMIT: + case ZFS_PROP_VOLSIZE: + case ZFS_PROP_SNAPDEV: + case ZFS_PROP_VERSION: + default: + if (prop != ZPROP_INVAL || + zfs_prop_userquota(propname) == B_FALSE) + break; + if (atomic == B_TRUE) + err = SET_ERROR(ENOTSUP); + } + if (err == 0) { nvlist_t *tnvl = NULL; err = zfs_prop_set_special(dsname, source, pair); @@ -2705,7 +2724,8 @@ zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl, } if (!nvlist_empty(genericnvl) && - dsl_props_set(dsname, source, genericnvl) != 0) { + (rv = dsl_props_set(dsname, source, genericnvl)) != 0 && + atomic == B_FALSE) { /* * If this fails, we still want to set as many properties as we * can, so try setting them individually. @@ -2807,7 +2827,8 @@ clear_received_props(const char *dsname, nvlist_t *props, */ zprop_source_t flags = (ZPROP_SRC_NONE | (dsl_prop_get_hasrecvd(dsname) ? ZPROP_SRC_RECEIVED : 0)); - err = zfs_set_prop_nvlist(dsname, flags, cleared_props, NULL); + err = zfs_set_prop_nvlist(dsname, flags, cleared_props, NULL, + B_FALSE); } nvlist_free(cleared_props); return (err); @@ -2851,7 +2872,8 @@ zfs_ioc_set_prop(zfs_cmd_t *zc) errors = fnvlist_alloc(); if (error == 0) - error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, errors); + error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, errors, + B_FALSE); if (zc->zc_nvlist_dst != 0 && errors != NULL) { (void) put_nvlist(zc, errors); @@ -3351,7 +3373,7 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) */ if (error == 0) { error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, - nvprops, outnvl); + nvprops, outnvl, B_FALSE); if (error != 0) (void) dsl_destroy_head(fsname); } @@ -3399,7 +3421,7 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) */ if (error == 0) { error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL, - nvprops, outnvl); + nvprops, outnvl, B_FALSE); if (error != 0) (void) dsl_destroy_head(fsname); } @@ -4244,7 +4266,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) if (props_error == 0) { (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, - props, errors); + props, errors, B_FALSE); } } @@ -4329,7 +4351,7 @@ zfs_ioc_recv(zfs_cmd_t *zc) if (origprops != NULL && zfs_set_prop_nvlist(tofs, (first_recvd_props ? ZPROP_SRC_LOCAL : ZPROP_SRC_RECEIVED), - origprops, NULL) != 0) { + origprops, NULL, B_FALSE) != 0) { /* * We stashed the original properties but failed to * restore them. @@ -5550,14 +5572,12 @@ static int zfs_stable_ioc_set_props(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, nvlist_t *opts, uint64_t version) { - zprop_source_t source; - boolean_t received; + zprop_source_t source = ZPROP_SRC_LOCAL; int error = 0; - received = nvlist_exists(opts, "received"); - source = (received ? ZPROP_SRC_RECEIVED : ZPROP_SRC_LOCAL); - if (received) { + if (nvlist_exists(opts, "received")) { nvlist_t *origprops; + source = ZPROP_SRC_RECEIVED; if (dsl_prop_get_received(fsname, &origprops) == 0) { (void) clear_received_props(fsname, origprops, innvl); @@ -5568,7 +5588,8 @@ zfs_stable_ioc_set_props(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, } if (error == 0) - error = zfs_set_prop_nvlist(fsname, source, innvl, outnvl); + error = zfs_set_prop_nvlist(fsname, source, innvl, outnvl, + nvlist_exists(opts, "noatomic") == B_FALSE); return (error); } From 4f9bada48b284d3b21155187194cb2c2599121b5 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 15 May 2015 10:23:39 -0400 Subject: [PATCH 22/40] Implement lzc_list() This implements a stable zfs list API. inspired by the CLI `zfs list`. It unifies several existing API calls into a single call that provides an almost complete subset of the functionality provided by `zfs list`. The existing API calls that this supercedes are: - ZFS_IOC_OBJSET_STATS - ZFS_IOC_OBJSET_ZPLPROPS - ZFS_IOC_DATASET_LIST_NEXT - ZFS_IOC_SNAPSHOT_LIST_NEXT - ZFS_IOC_GET_BOOKMARKS (stable lzc API) Since ZFS_IOC_GET_BOOKMARKS is a stable API, it has been left untouched. The functionality absent from the API that is present in `zfs list` is the ability to sort and request data on specific properties. Under this API, userland is (still) expected to sort and all property data is returned. Programming documentation on the API is included a comment in libzfs_core.c. Signed-off-by: Richard Yao --- cmd/zfs/zfs_iter.c | 60 ++--- cmd/zfs/zfs_iter.h | 1 + cmd/zfs/zfs_main.c | 13 +- include/libzfs.h | 2 + include/libzfs_core.h | 1 + include/sys/dmu_objset.h | 7 + include/sys/dsl_prop.h | 1 + include/sys/zfs_ioctl.h | 8 + lib/libzfs/libzfs_dataset.c | 5 +- lib/libzfs/libzfs_iter.c | 172 +++++++++++++ lib/libzfs_core/libzfs_core.c | 145 ++++++++++- module/zfs/dmu_objset.c | 67 +++++ module/zfs/dsl_prop.c | 20 +- module/zfs/zfs_ioctl.c | 459 +++++++++++++++++++++++++++++++++- 14 files changed, 902 insertions(+), 59 deletions(-) diff --git a/cmd/zfs/zfs_iter.c b/cmd/zfs/zfs_iter.c index 2c16f6981bb2..a10f3bc9a44d 100644 --- a/cmd/zfs/zfs_iter.c +++ b/cmd/zfs/zfs_iter.c @@ -94,7 +94,6 @@ zfs_callback(zfs_handle_t *zhp, void *data) callback_data_t *cb = data; boolean_t dontclose = B_FALSE; boolean_t include_snaps = zfs_include_snapshots(zhp, cb); - boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK); if ((zfs_get_type(zhp) & cb->cb_types) || ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) { @@ -126,26 +125,6 @@ zfs_callback(zfs_handle_t *zhp, void *data) } } - /* - * Recurse if necessary. - */ - if (cb->cb_flags & ZFS_ITER_RECURSE && - ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 || - cb->cb_depth < cb->cb_depth_limit)) { - cb->cb_depth++; - if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) - (void) zfs_iter_filesystems(zhp, zfs_callback, data); - if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | - ZFS_TYPE_BOOKMARK)) == 0) && include_snaps) - (void) zfs_iter_snapshots(zhp, - (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback, - data); - if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | - ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks) - (void) zfs_iter_bookmarks(zhp, zfs_callback, data); - cb->cb_depth--; - } - if (!dontclose) zfs_close(zhp); @@ -378,6 +357,8 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types, int ret = 0; zfs_node_t *node; uu_avl_walk_t *walk; + zfs_type_t argtype; + boolean_t limit_specified = !!(flags & ZFS_ITER_DEPTH_LIMIT); avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT); @@ -386,6 +367,10 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types, nomem(); cb.cb_sortcol = sortcol; + /* + * XXX: We are phasing out the legacy recursive interface in + * favor of the new stable list API. + */ cb.cb_flags = flags; cb.cb_proplist = proplist; cb.cb_types = types; @@ -431,38 +416,35 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types, if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) nomem(); + /* + * zfs_iter_generic() lets the kernel worry about default types. + */ + argtype = types * !!(flags & ZFS_ITER_TYPES_SPECIFIED); if (argc == 0) { /* * If given no arguments, iterate over all datasets. */ - cb.cb_flags |= ZFS_ITER_RECURSE; - ret = zfs_iter_root(g_zfs, zfs_callback, &cb); + ret = zfs_iter_generic(g_zfs, NULL, argtype, + (limit_specified) ? limit : -1, limit_specified, + zfs_callback, &cb); } else { int i; zfs_handle_t *zhp; - zfs_type_t argtype; - - /* - * If we're recursive, then we always allow filesystems as - * arguments. If we also are interested in snapshots, then we - * can take volumes as well. - */ - argtype = types; - if (flags & ZFS_ITER_RECURSE) { - argtype |= ZFS_TYPE_FILESYSTEM; - if (types & ZFS_TYPE_SNAPSHOT) - argtype |= ZFS_TYPE_VOLUME; - } for (i = 0; i < argc; i++) { if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) { zhp = zfs_path_to_zhandle(g_zfs, argv[i], - argtype); + (flags & ZFS_ITER_RECURSE) ? 0 : argtype); } else { - zhp = zfs_open(g_zfs, argv[i], argtype); + zhp = zfs_open(g_zfs, argv[i], + (flags & ZFS_ITER_RECURSE) ? 0 : argtype); } if (zhp != NULL) - ret |= zfs_callback(zhp, &cb); + ret |= zfs_iter_generic(zfs_get_handle(zhp), + zfs_get_name(zhp), argtype, + (limit_specified) ? limit : (flags & + ZFS_ITER_RECURSE) ? -1 : 0, + limit_specified, zfs_callback, &cb); else ret = 1; } diff --git a/cmd/zfs/zfs_iter.h b/cmd/zfs/zfs_iter.h index 2697fbdca1df..845f92712163 100644 --- a/cmd/zfs/zfs_iter.h +++ b/cmd/zfs/zfs_iter.h @@ -47,6 +47,7 @@ typedef struct zfs_sort_column { #define ZFS_ITER_RECVD_PROPS (1 << 4) #define ZFS_ITER_LITERAL_PROPS (1 << 5) #define ZFS_ITER_SIMPLE (1 << 6) +#define ZFS_ITER_TYPES_SPECIFIED (1 << 7) int zfs_for_each(int, char **, int options, zfs_type_t, zfs_sort_column_t *, zprop_list_t **, int, zfs_iter_f, void *); diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 6fb35595ccc9..8f1a21b86987 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -1709,7 +1709,7 @@ zfs_do_get(int argc, char **argv) case 't': types = 0; - flags &= ~ZFS_ITER_PROP_LISTSNAPS; + flags |= ZFS_ITER_TYPES_SPECIFIED; while (*optarg != '\0') { static char *type_subopts[] = { "filesystem", "volume", "snapshot", "bookmark", @@ -1785,6 +1785,9 @@ zfs_do_get(int argc, char **argv) cb.cb_first = B_TRUE; + if (argc > 0 && (flags & ZFS_ITER_RECURSE) == 0) + flags |= ZFS_ITER_DEPTH_LIMIT; + /* run for each object */ ret = zfs_for_each(argc, argv, flags, types, NULL, &cb.cb_proplist, limit, get_callback, &cb); @@ -3033,14 +3036,13 @@ zfs_do_list(int argc, char **argv) static char default_fields[] = "name,used,available,referenced,mountpoint"; int types = ZFS_TYPE_DATASET; - boolean_t types_specified = B_FALSE; char *fields = NULL; list_cbdata_t cb = { 0 }; char *value; int limit = 0; int ret = 0; zfs_sort_column_t *sortcol = NULL; - int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS; + int flags = ZFS_ITER_ARGS_CAN_BE_PATHS; /* check options */ while ((c = getopt(argc, argv, "HS:d:o:prs:t:")) != -1) { @@ -3079,8 +3081,7 @@ zfs_do_list(int argc, char **argv) break; case 't': types = 0; - types_specified = B_TRUE; - flags &= ~ZFS_ITER_PROP_LISTSNAPS; + flags |= ZFS_ITER_TYPES_SPECIFIED; while (*optarg != '\0') { static char *type_subopts[] = { "filesystem", "volume", "snapshot", "snap", "bookmark", @@ -3141,7 +3142,7 @@ zfs_do_list(int argc, char **argv) /* * If "-o space" and no types were specified, don't display snapshots. */ - if (strcmp(fields, "space") == 0 && types_specified == B_FALSE) + if (strcmp(fields, "space") == 0 && !(flags & ZFS_ITER_TYPES_SPECIFIED)) types &= ~ZFS_TYPE_SNAPSHOT; /* diff --git a/include/libzfs.h b/include/libzfs.h index db8ee7167e17..ffbd444e286b 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -554,6 +554,8 @@ void zprop_print_one_property(const char *, zprop_get_cbdata_t *, * Iterator functions. */ typedef int (*zfs_iter_f)(zfs_handle_t *, void *); +extern int zfs_iter_generic(libzfs_handle_t *, const char *, zfs_type_t, + int64_t, boolean_t, zfs_iter_f, void *); extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *); diff --git a/include/libzfs_core.h b/include/libzfs_core.h index bf179e6055d7..db0171d61397 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -38,6 +38,7 @@ extern "C" { int libzfs_core_init(void); void libzfs_core_fini(void); +int lzc_list(const char *, nvlist_t *); int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); int lzc_create(const char *, dmu_objset_type_t, nvlist_t *); int lzc_clone(const char *, const char *, nvlist_t *); diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h index 10c4597d0d9a..96b29faad4b6 100644 --- a/include/sys/dmu_objset.h +++ b/include/sys/dmu_objset.h @@ -176,6 +176,13 @@ int dmu_fsname(const char *snapname, char *buf); void dmu_objset_evict_done(objset_t *os); +/* Code for handling userspace interface */ +extern const char *dmu_objset_types[]; + +const char *dmu_objset_type_name(dmu_objset_type_t type); +nvlist_t *dmu_objset_stats_nvlist(dmu_objset_stats_t *stat); +int dmu_objset_stat_nvlts(nvlist_t *nvl, dmu_objset_stats_t *stat); + void dmu_objset_init(void); void dmu_objset_fini(void); diff --git a/include/sys/dsl_prop.h b/include/sys/dsl_prop.h index 5fe18d6a7c55..c77b85d71980 100644 --- a/include/sys/dsl_prop.h +++ b/include/sys/dsl_prop.h @@ -66,6 +66,7 @@ int dsl_prop_get(const char *ddname, const char *propname, int dsl_prop_get_integer(const char *ddname, const char *propname, uint64_t *valuep, char *setpoint); int dsl_prop_get_all(objset_t *os, nvlist_t **nvp); +int dsl_prop_get_all_new(objset_t *os, nvlist_t **nvp); int dsl_prop_get_received(const char *dsname, nvlist_t **nvp); int dsl_prop_get_ds(struct dsl_dataset *ds, const char *propname, int intsz, int numints, void *buf, char *setpoint); diff --git a/include/sys/zfs_ioctl.h b/include/sys/zfs_ioctl.h index 09a96c043bf0..c4113e3e4c80 100644 --- a/include/sys/zfs_ioctl.h +++ b/include/sys/zfs_ioctl.h @@ -357,6 +357,14 @@ typedef struct zfs_cmd { zfs_stat_t zc_stat; } zfs_cmd_t; +typedef struct zfs_pipe_record { + uint32_t zpr_data_size; /* Payload size */ + uint8_t zpr_header_size;/* Extension space after 8 bytes */ + uint8_t zpr_err; /* Return code */ + uint8_t zpr_endian; /* Endian bit: 0 is BE, 1 is LE */ + uint8_t zpr_reserved; /* Reserved space */ +} zfs_pipe_record_t; + typedef struct zfs_useracct { char zu_domain[256]; uid_t zu_rid; diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index f416ac6729b4..66af47c496d0 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -644,7 +644,10 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types) return (NULL); } - if (!(types & zhp->zfs_type)) { + /* + * types == 0 is set when we have the kernel check the type for us. + */ + if (types && !(types & zhp->zfs_type)) { (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); zfs_close(zhp); return (NULL); diff --git a/lib/libzfs/libzfs_iter.c b/lib/libzfs/libzfs_iter.c index 5c1cf966a543..6f1852e04668 100644 --- a/lib/libzfs/libzfs_iter.c +++ b/lib/libzfs/libzfs_iter.c @@ -35,6 +35,12 @@ #include "libzfs_impl.h" +/* + * XXX: Workaround for conflicting type declarations for sa_handle_t between + * sys/sa.h and libshare.h + */ +extern int dmu_objset_stat_nvlts(nvlist_t *nvl, dmu_objset_stats_t *stat); + int zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data) { @@ -57,6 +63,172 @@ zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data) return (0); } +static char *zfs_types[] = { "filesystem", "snapshot", "volume", "pool", + "bookmark" }; + +#define ZFS_TYPE_COUNT (sizeof (zfs_types) / sizeof (&zfs_types[0])) + +static nvlist_t * +zfs_type_to_nvl(zfs_type_t type) +{ + nvlist_t *nvl = fnvlist_alloc(); + int i; + + for (i = 0; i < ZFS_TYPE_COUNT; i++) + if (type & (1 << i)) + fnvlist_add_boolean(nvl, zfs_types[i]); + + return (nvl); +} + +/* + * Iterate over all children filesystems (stable) + */ +int +zfs_iter_generic(libzfs_handle_t *hdl, const char *name, zfs_type_t type, + int64_t depth, boolean_t depth_specified, zfs_iter_f func, void *data) +{ + zfs_cmd_t zc = {"\0"}; + zfs_handle_t *nzhp; + nvlist_t *tnvl; + nvlist_t *opts; + int fildes[2]; + zfs_pipe_record_t zpr; + int ret; + + if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) + return (-1); + + ret = pipe(fildes); + if (ret == -1) { + switch (errno) { + default: + ret = zfs_standard_error(hdl, errno, + dgettext(TEXT_DOMAIN, + "cannot iterate filesystems")); + break; + } + } + + opts = fnvlist_alloc(); + if (depth_specified) { + switch (depth) { + case -1: + fnvlist_add_boolean(opts, "recurse"); + default: + if (depth < 0) { + fnvlist_free(opts); + return (-1); + } + fnvlist_add_uint64(opts, "recurse", depth); + } + } else + fnvlist_add_boolean(opts, "recurse"); + + tnvl = zfs_type_to_nvl(type); + fnvlist_add_nvlist(opts, "type", tnvl); + fnvlist_add_int32(opts, "fd", fildes[1]); + + if ((ret = lzc_list(name, opts)) != 0) { + fnvlist_free(opts); + close(fildes[0]); + close(fildes[1]); + return (ret); + } + fnvlist_free(tnvl); + fnvlist_free(opts); + + while ((ret = read(fildes[0], &zpr, + sizeof (zfs_pipe_record_t))) == sizeof (uint64_t) && + zpr.zpr_data_size != 0 && zpr.zpr_err == 0) { + nvlist_t *nvl, *nvl_prop, *nvl_dds; + char *name; +#ifdef _LITTLE_ENDIAN + uint32_t size = (zpr.zpr_endian) ? zpr.zpr_data_size : + BSWAP_32(zpr.zpr_data_size); +#else + uint32_t size = (zpr.zpr_endian) ? BSWAP_32(zpr.zpr_data_size) : + zpr.zpr_data_size; +#endif + char *buf = umem_alloc(size, UMEM_NOFAIL); + + ret = read(fildes[0], buf, size); + + if (size != ret || (ret = nvlist_unpack(buf + + zpr.zpr_header_size, size, &nvl, 0)) != 0) { + umem_free(buf, size); + goto out; + } + + if ((ret = nvlist_lookup_nvlist(nvl, "properties", &nvl_prop)) + != 0 || + (ret = nvlist_lookup_string(nvl, "name", &name)) != 0 || + (ret = nvlist_lookup_nvlist(nvl, "dmu_objset_stats", + &nvl_dds)) != 0 || + (ret = dmu_objset_stat_nvlts(nvl_dds, &zc.zc_objset_stats)) + != 0) { + ret = EINVAL; + umem_free(buf, size); + goto out; + } + + strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); + umem_free(buf, size); + + zc.zc_nvlist_dst_size = fnvlist_size(nvl_prop); + if ((ret = zcmd_expand_dst_nvlist(hdl, &zc))) { + if (ret == -1) + ret = ENOMEM; + goto out; + } + + ret = nvlist_pack(nvl_prop, (char **) &zc.zc_nvlist_dst, + &zc.zc_nvlist_dst_size, NV_ENCODE_NATIVE, 0); + + zc.zc_nvlist_dst_filled = B_TRUE; + + /* + * Errors here do not make sense, so we bail. + */ + if (strchr(name, '#') != NULL) { + zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); + if (zhp == NULL) { + ret = ENOMEM; + goto out; + } + zhp->zfs_hdl = hdl; + switch (zc.zc_objset_stats.dds_type) { + case DMU_OST_ZFS: + zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; + break; + case DMU_OST_ZVOL: + zhp->zfs_head_type = ZFS_TYPE_VOLUME; + break; + default: + ret = EINVAL; + goto out; + } + nzhp = make_bookmark_handle(zhp, name, nvl_prop); + free(zhp); + if (nzhp == NULL) + continue; + } else if ((ret != 0) || + (nzhp = make_dataset_handle_zc(hdl, &zc)) == NULL) { + ret = EINVAL; + goto out; + } + + if ((ret = func(nzhp, data)) != 0) + goto out; + } + +out: + close(fildes[0]); + close(fildes[1]); + zcmd_free_nvlists(&zc); + return ((ret < 0) ? ret : 0); +} + static int zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc) { diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index c474a6a94268..2a8dead1d4f9 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -127,7 +127,8 @@ lzc_ioctl_impl(zfs_ioc_t ioc, const char *name, ASSERT3S(g_refcount, >, 0); - (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); + if (name) + (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); packed = fnvlist_pack(source, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; @@ -804,3 +805,145 @@ lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist) return (error); } + +/* + * List DSL directory/directories + * + * This is an asynchronous API call. The caller passes a file descriptor + * through which output is received. The file descriptor should typically be + * the send side of a pipe, but this is not required. + * + * Preliminary error checks are done prior to the start of output and if + * successful, a return code of zero is provided. If unsuccessful, a non-zero + * error code is passed. + * + * The opts field is an nvlist which supports the following properties: + * + * Name Type Description + * "recurse" boolean/uint64 List output for children. + * "type" nvlist List only types specified. + * + * If the passed name is that of a bookmark or snapshot, the recurse field is + * ignored. If all children are desired, recurse should be set to be a boolean + * type. If a recursion limit is desired, recurses hould be a uint64_t. If no + * type is specified, a default behavior consistent with the zfs list command + * is provided. Valid children of the type nvlist are: + * + * Name Type Description + * "all" boolean List output for all types + * "bookmark" boolean List output for bookmarks + * "filesystem" boolean List output for filesystems + * "snap" boolean List output for snapshots + * "snapshot" boolean List output for snapshots + * "volume" boolean List output for volumes + * + * Whenever a boolean type is specified, any type may be passed and be + * considered boolean. However, future extensions may accept alternate types + * and consequently, backward compatibility is only guarenteed to callers + * passing a boolean type that contains no value. A boolean that contains + * B_TRUE or B_FALSE is considered a separate type from a boolean that contains + * no value. Additionally, future enhancements to zfs may create a new type and + * callers that only wish to handle existing types should specify them + * explicitly rather than relying on the default behavior. + * + * The parent-child relationship is obeyed such all children of each + * pool/directory are output alongside their parents. However, no guarantees + * are made with regard to post-order/pre-order traversal or the order of + * bookmarks/snapshots, such that the order is allowed to change. Userland + * applications that are sensitive to a particular output order are expected to + * sort. + * + * The output consists of a record header followed immediately by XDR-encoded + * nvlist. The header format is as follows: + * + * Offset Size Description + * 0 bytes 4 bytes XDR-nvlist size (unsigned) + * 4 bytes 1 byte Header extension space (unsigned) + * 5 bytes 1 byte Return code (unsigned) + * 6 bytes 1 byte Endian bit (0 is BE, 1 is LE) + * 7 bytes 1 byte Reserved + * + * Errors obtaining information for any record will be contained in the return + * code. The output for any record whose header return code contains an error + * is a XDR encoded nvlist whose contents are undefined, unless the size + * provided in the header is zero, in which case the output for that record is + * empty. The receiver is expected to check the endian bit field before + * processing the XDR-nvlist size and perform a byte-swap operation on the + * value should the endian-ness differ. + * + * Non-zero values in the reserved field and upper bits of the endian field + * imply a back-incompatible change. If the header extension field is non-zero + * when neither the reserved field nor the upper bits of the endian field are + * non-zero, the header should be assumed to have been extended in a + * backward-compatible way and the XDR-nvlist of the specified size shall + * follow the extended header. The lzc_list() library call will always request + * API version 0 request as part of the ioctl to userland. Consequently, the + * kernel will return an API version 0 compatible-stream unless a change is + * requested via a future extension to the opts nvlist. + * + * The nvlist will have the following members: + * + * Name Type Description + * "name" string SPA/DSL name + * "dmu_objset_stats" nvlist DMU Objset Stats + * "properties" nvlist DSL properties + * + * Additional members may be added in future extensions. + * + * The "dmu_objset_stats" will have the following members: + * + * Name Type Description + * "dds_num_clones" uint64_t Number of clones + * "dds_creation_txg" uint64_t Creation transaction group + * "dds_guid" uint64_t Globally unique identifier + * "dds_type" string Type + * "dds_is_snapshot" boolean Is a snapshot + * "dds_inconsistent" boolean Is being received or destroyed + * "dds_origin" string Name of parent + * + * Additional members may be added in future extensions. + * + * The "dds_" prefix stands for "DSL Dataset". "dds_type" is a string + * representation of internal object types. Valid values at this time are: + * + * Name Public Description + * "NONE" No Uninitialized value + * "META" No Metadata + * "ZPL" Yes Dataset + * "ZVOL" Yes Volume + * "OTHER" No Undefined + * "ANY" No Open + * + * Only the public values will be returned for any output. The return of a + * value not on this list implies a record for a new storage type. The output + * should be consistent with existing types and the receiver can elect to + * either handle it in a manner consistent with existing types or skip it. + * Under no circumstance will an unlisted type be returned when types were + * explicitly provided via the opts nvlist. + * + * On bookmarks, the "dmu_objset_stats" of the parent DSL Dataset shall be + * returned. Consequently, "dds_is_snapshot" shall be false and identification + * of bookmarks shall be done by checking for the '#' character in the "name" + * member of the top level nvlist. This is done so that the type of the + * bookmarked DSL dataset may be known. + * + * End of output shall be signified by NULL record header. Userland is expected + * to close the file descriptor. Early termination can be signaled from + * userland by closing the file descriptor. + * + * The design of the output is intended to enable userland to perform readahead + * on the file descriptor. On certain platforms, libc may provide output + * buffering. Userland libraries and applications electing to perform readahead + * should take care not to block on a partially filled buffer when an end of + * stream NULL record is returned. + */ +int +lzc_list(const char *name, nvlist_t *opts) +{ + int error; + nvlist_t *innvl = fnvlist_alloc(); + + error = lzc_ioctl("zfs_list", name, innvl, opts, NULL, 0); + + return (error); +} diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 79f8268f8153..512ebe15b176 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -26,6 +26,7 @@ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. * Copyright (c) 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2015, STRATO AG, Inc. All rights reserved. + * Copyright (c) 2015 by ClusterHQ, Inc. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -2016,6 +2017,72 @@ dmu_fsname(const char *snapname, char *buf) return (0); } +/* Code for handling userspace interface */ +const char *dmu_objset_types[DMU_OST_NUMTYPES] = { + "NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" }; + +#define DMU_OT_COUNT (sizeof (dmu_objset_types) /\ + sizeof (&dmu_objset_types[0])) + +const char * +dmu_objset_type_name(dmu_objset_type_t type) +{ + return ((type < DMU_OST_NUMTYPES) ? dmu_objset_types[type] : NULL); +} + +nvlist_t * +dmu_objset_stats_nvlist(dmu_objset_stats_t *stat) +{ + nvlist_t *nvl = fnvlist_alloc(); + + nvlist_add_uint64(nvl, "dds_num_clones", stat->dds_num_clones); + nvlist_add_uint64(nvl, "dds_creation_txg", stat->dds_creation_txg); + nvlist_add_uint64(nvl, "dds_guid", stat->dds_guid); + + fnvlist_add_string(nvl, "dds_type", + dmu_objset_type_name(stat->dds_type)); + + fnvlist_add_boolean_value(nvl, "dds_is_snapshot", + stat->dds_is_snapshot); + fnvlist_add_boolean_value(nvl, "dds_inconsistent", + stat->dds_inconsistent); + + fnvlist_add_string(nvl, "dds_origin", stat->dds_origin); + + return (nvl); +} + +int +dmu_objset_stat_nvlts(nvlist_t *nvl, dmu_objset_stats_t *stat) +{ + char *type; + boolean_t issnap, inconsist; + int i; + + if (nvlist_lookup_uint64(nvl, "dds_num_clones", + &stat->dds_num_clones) || + nvlist_lookup_uint64(nvl, "dds_creation_txg", + &stat->dds_creation_txg) || + nvlist_lookup_uint64(nvl, "dds_guid", &stat->dds_guid) || + nvlist_lookup_string(nvl, "dds_type", &type) || + nvlist_lookup_boolean_value(nvl, "dds_is_snapshot", &issnap) || + nvlist_lookup_boolean_value(nvl, "dds_inconsistent", &inconsist)) + return (EINVAL); + + stat->dds_inconsistent = inconsist; + stat->dds_is_snapshot = issnap; + + for (i = 0; i < DMU_OT_COUNT; i++) { + if (strcmp(dmu_objset_types[i], type) == 0) { + stat->dds_type = i; + return (0); + } + } + + return (EINVAL); +} + + #if defined(_KERNEL) && defined(HAVE_SPL) EXPORT_SYMBOL(dmu_objset_zil); EXPORT_SYMBOL(dmu_objset_pool); diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 0188decec52d..bf63c1ecc043 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -984,7 +984,8 @@ typedef enum dsl_prop_getflags { DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */ DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */ DSL_PROP_GET_LOCAL = 0x4, /* local properties */ - DSL_PROP_GET_RECEIVED = 0x8 /* received properties */ + DSL_PROP_GET_RECEIVED = 0x8, /* received properties */ + DSL_PROP_GET_INDEX_STR = 0x10 /* index properties as strings */ } dsl_prop_getflags_t; static int @@ -1090,6 +1091,16 @@ dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, VERIFY(nvlist_add_string(propval, ZPROP_VALUE, tmp) == 0); kmem_free(tmp, za.za_num_integers); + } else if ((flags & DSL_PROP_GET_INDEX_STR) && + zfs_prop_get_type(prop) == PROP_TYPE_INDEX) { + /* + * Index property (returned as string) + */ + const char *strval; + VERIFY0(zfs_prop_index_to_string(prop, + za.za_first_integer, &strval)); + VERIFY0(nvlist_add_string(propval, ZPROP_VALUE, + strval)); } else { /* * Integer property @@ -1205,6 +1216,13 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp) return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0)); } +int +dsl_prop_get_all_new(objset_t *os, nvlist_t **nvp) +{ + return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, + DSL_PROP_GET_INDEX_STR)); +} + int dsl_prop_get_received(const char *dsname, nvlist_t **nvp) { diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 7165bd1f65ba..00a9286c2e76 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -212,7 +212,9 @@ typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, nvlist_t *, cred_t *); typedef enum { NO_NAME, POOL_NAME, - DATASET_NAME + POOL_NAME_OR_EMPTY, + DATASET_NAME, + DATASET_NAME_OR_EMPTY, } zfs_ioc_namecheck_t; typedef enum { @@ -2032,6 +2034,8 @@ zfs_ioc_vdev_setfru(zfs_cmd_t *zc) * nv nvlist handle * stat pointer to dmu_objset_stats_t for output * os Objset of filesystem (held by caller) + * str_indices Whether index properties should be translated + * into strings * * outputs: * *nv property nvlist @@ -2044,10 +2048,12 @@ zfs_ioc_objset_stats_impl_nohold(nvlist_t **nv, dmu_objset_stats_t *stat, objset_t *os, boolean_t str_indices) { int error = 0; + int (*prop_func)(objset_t *, nvlist_t **) = (str_indices) ? + dsl_prop_get_all_new : dsl_prop_get_all; dmu_objset_fast_stat(os, stat); - if (nv != 0 && (error = dsl_prop_get_all(os, nv)) == 0) { + if (nv != 0 && (error = prop_func(os, nv)) == 0) { dmu_objset_stats(os, *nv); /* * NB: zvol_get_stats() will read the objset contents, @@ -2269,12 +2275,12 @@ zfs_ioc_dataset_list_next_impl(zfs_list_t *zl) p = strrchr(zl->zl_name, '/'); if (p == NULL || p[1] != '\0') - (void) strlcat(zl->zl_name, "/", sizeof (zl->zl_name)); + (void) strlcat(zl->zl_name, "/", MAXPATHLEN); p = zl->zl_name + strlen(zl->zl_name); do { error = dmu_dir_list_next(os, - sizeof (zl->zl_name) - (p - zl->zl_name), p, + MAXPATHLEN - (p - zl->zl_name), p, NULL, &zl->zl_cookie); if (error == ENOENT) error = SET_ERROR(ESRCH); @@ -2324,13 +2330,13 @@ zfs_ioc_snapshot_list_next_impl(zfs_list_t *zl, boolean_t simple) * A dataset name of maximum length cannot have any snapshots, * so exit immediately. */ - if (strlcat(zl->zl_name, "@", sizeof (zl->zl_name)) >= MAXNAMELEN) { + if (strlcat(zl->zl_name, "@", MAXPATHLEN) >= MAXNAMELEN) { dmu_objset_rele(os, FTAG); return (SET_ERROR(ESRCH)); } error = dmu_snapshot_list_next(os, - sizeof (zl->zl_name) - strlen(zl->zl_name), + MAXPATHLEN - strlen(zl->zl_name), zl->zl_name + strlen(zl->zl_name), &zl->zl_obj, &zl->zl_cookie, NULL); @@ -5472,7 +5478,7 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) static int zfs_stable_ioc_send_progress(const char *snapname, nvlist_t *innvl, - nvlist_t *outnvl, nvlist_t *opts, uint64_t version) + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) { dsl_pool_t *dp; dsl_dataset_t *ds; @@ -5530,7 +5536,6 @@ zfs_stable_ioc_promote(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, dsl_dataset_t *clone; dsl_dataset_t *origin = NULL; dsl_dir_t *dd; - char *cp; int error; error = dsl_pool_hold(fsname, FTAG, &dp); @@ -5623,6 +5628,423 @@ LIBZFS_CORE_WRAPPER_FUNC(rollback) LIBZFS_CORE_WRAPPER_FUNC(bookmark) LIBZFS_CORE_WRAPPER_FUNC(destroy_bookmarks) +#define DLS_TRAVERSE_ALL (DLS_TRAVERSE_FILESYSTEM | \ + DLS_TRAVERSE_SNAPSHOT | \ + DLS_TRAVERSE_VOLUME | \ + DLS_TRAVERSE_BOOKMARK) + +typedef enum dls_flag { + DLS_RECURSE = 1 << 0, + DLS_TRAVERSE_FILESYSTEM = 1 << 1, + DLS_TRAVERSE_SNAPSHOT = 1 << 2, + DLS_TRAVERSE_VOLUME = 1 << 3, + DLS_TRAVERSE_BOOKMARK = 1 << 4, +} dls_flag_t; + +typedef struct dls { + int dls_fd; + struct task_struct *dls_task; + uf_info_t *dls_fip; + vnode_t *dls_vp; + uint64_t dls_depth; + dls_flag_t dls_flags; + const char *dls_fsname; +} dls_t; + +static int +dump_zpr(nvlist_t *nvl, vnode_t *vp) { + size_t nvsize; + ssize_t resid; + char *packed; + zfs_pipe_record_t *zpr; + int err; + + ASSERT(sizeof (zfs_pipe_record_t) == sizeof (uint64_t)); + + nvsize = fnvlist_size(nvl); + if (nvsize > (1 << (sizeof (zpr->zpr_data_size) + 8))) + return (EOVERFLOW); + + /* + * Allocate memory ourselves so that we can include space for the + * header. + */ + zpr = kmem_alloc(nvsize + sizeof (zfs_pipe_record_t), KM_SLEEP); + + /* Setup header */ + bzero(zpr, sizeof (zfs_pipe_record_t)); + zpr->zpr_data_size = (uint32_t) nvsize; +#ifdef _LITTLE_ENDIAN + zpr->zpr_endian = 1; +#endif + + packed = (char *)(zpr + 1); + err = nvlist_pack(nvl, &packed, &nvsize, NV_ENCODE_XDR, 0); + + if (err) + goto out; + + err = vn_rdwr(UIO_WRITE, vp, (caddr_t) zpr, nvsize + + sizeof (zfs_pipe_record_t), 0, UIO_SYSSPACE, FAPPEND, + RLIM64_INFINITY, CRED(), &resid); + +out: + kmem_free(zpr, nvsize + sizeof (zfs_pipe_record_t)); + + return (err); +} + +#define STRLEN(s) (sizeof (s)/sizeof (s[0]) - 1) + +static int +dump_fs(vnode_t *vp, const char *fsname, nvlist_t *nvprops, dmu_objset_stats_t + *objset_stats) { + int err; + nvlist_t *outnvl = fnvlist_alloc(); + + fnvlist_add_string(outnvl, "name", fsname); + + if (!nvlist_empty(nvprops)) + fnvlist_add_nvlist(outnvl, "properties", nvprops); + + if (objset_stats != NULL) { + nvlist_t *nvl = dmu_objset_stats_nvlist(objset_stats); + fnvlist_add_nvlist(outnvl, "dmu_objset_stats", nvl); + fnvlist_free(nvl); + } + + err = dump_zpr(outnvl, vp); + fnvlist_free(outnvl); + return (err); +} + +static int +dump_ds(dsl_dataset_t *ds, boolean_t recurse, void *data) +{ + dls_t *dls = data; + static const size_t fsname_len = MAXNAMELEN + STRLEN(MOS_DIR_NAME) + 1; + dsl_pool_t *dp; + nvlist_t *nvl; + objset_t *osp; + char *fsname; + dmu_objset_stats_t objset_stats; + boolean_t issnap; + int err; + + dp = ds->ds_dir->dd_pool; + dmu_objset_from_ds(ds, &osp); + err = zfs_ioc_objset_stats_impl_nohold(&nvl, + &objset_stats, osp, B_TRUE); + if (err) + return (err); + + fsname = kmem_alloc(fsname_len, KM_SLEEP); + dmu_objset_name(osp, fsname); + + /* Restrict access to hidden datasets from zones */ + if (dataset_name_hidden(fsname)) { + fnvlist_free(nvl); + kmem_free(fsname, fsname_len); + return (0); + } + + issnap = objset_stats.dds_is_snapshot != 0; + ASSERT(issnap == ((strchr(fsname, '@') != NULL))); + + switch (dmu_objset_type(osp)) { + case DMU_OST_ZFS: + if (!(issnap && (dls->dls_flags && + DLS_TRAVERSE_SNAPSHOT)) && + !(dls->dls_flags & DLS_TRAVERSE_FILESYSTEM)) + goto skip; + break; + case DMU_OST_ZVOL: + if (!(issnap && (dls->dls_flags && + DLS_TRAVERSE_SNAPSHOT)) && + !(dls->dls_flags & DLS_TRAVERSE_VOLUME)) + goto skip; + break; + default: + ASSERT(0); + goto skip; + } + + if (issnap && (dls->dls_flags & DLS_TRAVERSE_SNAPSHOT) && + dls->dls_fsname && (strchr(dls->dls_fsname, '@') != NULL) && + strcmp(dls->dls_fsname, fsname) != 0) + goto skip; + if (!issnap && dls->dls_fsname && + (strchr(dls->dls_fsname, '@') != NULL)) + goto skip; + + err = dump_fs(dls->dls_vp, fsname, nvl, &objset_stats); + +skip: + fnvlist_free(nvl); + if ((err == 0) && !issnap && recurse && + (dls->dls_flags & DLS_TRAVERSE_BOOKMARK)) { + nvlist_t *innvl = fnvlist_alloc(); + nvlist_t *outnvl = fnvlist_alloc(); + boolean_t one = (dls->dls_fsname && + strchr(dls->dls_fsname, '#') != NULL); + + fnvlist_add_boolean(innvl, zfs_prop_to_name(ZFS_PROP_GUID)); + fnvlist_add_boolean(innvl, + zfs_prop_to_name(ZFS_PROP_CREATETXG)); + fnvlist_add_boolean(innvl, + zfs_prop_to_name(ZFS_PROP_CREATION)); + + if (dsl_get_bookmarks_impl(ds, innvl, outnvl) == 0) { + nvpair_t *pair; + for (pair = nvlist_next_nvpair(outnvl, NULL); + pair != NULL; + pair = nvlist_next_nvpair(outnvl, pair)) { + nvlist_t *nvl = NULL; + char *bname = kmem_asprintf("%s#%s", fsname, + nvpair_name(pair)); + VERIFY0(nvpair_value_nvlist(pair, &nvl)); + + if (one && + strcmp(dls->dls_fsname, bname) == 0) { + strfree(bname); + continue; + } + + err = dump_fs(dls->dls_vp, bname, nvl, + &objset_stats); + strfree(bname); + if (err || one) + break; + + } + + } + fnvlist_free(innvl); + fnvlist_free(outnvl); + } + + kmem_free(fsname, fsname_len); + + return (err); +} + +int +dump_list_strategy_one(dsl_pool_t *dp, uint64_t dd_object, + int dmu_flags, dls_t *dls) +{ + int error; + + if (dls->dls_flags & DLS_TRAVERSE_SNAPSHOT) { + dmu_flags |= DS_FIND_SNAPSHOTS; + } else if (dls->dls_flags & DLS_RECURSE && + dp->dp_spa->spa_pool_props_object != 0) { + uint64_t listsnap = 0; + + (void) zap_lookup(dp->dp_meta_objset, + dp->dp_spa->spa_pool_props_object, + zpool_prop_to_name(ZPOOL_PROP_LISTSNAPS), + sizeof (uint64_t), 1, &listsnap); + + if (listsnap) + dmu_flags |= DS_FIND_SNAPSHOTS; + } + + error = dmu_objset_find_dp(dp, dd_object, &dump_ds, dls, + dmu_flags, dls->dls_depth); + + return (error); +} + +int +dump_list_strategy_impl(dls_t *dls) +{ + int error = 0; + spa_t *spa; + dsl_pool_t *dp; + + if (dls->dls_fsname) { + dsl_dir_t *dd; + int dmu_flags = DS_FIND_SERIALIZE; + char *dname; + char *c; + + + if (dls->dls_flags & DLS_RECURSE) + dmu_flags |= DS_FIND_CHILDREN; + + error = dsl_pool_hold(dls->dls_fsname, FTAG, &dp); + if (error != 0) + return (error); + + dname = strdup(dls->dls_fsname); + if ((c = strpbrk(dname, "@#"))) + c[0] = '\0'; + error = dsl_dir_hold(dp, dname, FTAG, &dd, NULL); + strcpy(dname, dls->dls_fsname); + strfree(dname); + if (error != 0) { + dsl_pool_rele(dp, FTAG); + return (error); + } + error = dump_list_strategy_one(dp, dd->dd_object, + dmu_flags, dls); + + dsl_dir_rele(dd, FTAG); + dsl_pool_rele(dp, FTAG); + + return (error); + } + + mutex_enter(&spa_namespace_lock); + for (spa = spa_next(NULL); spa != NULL; spa = spa_next(spa)) { + spa_open_ref(spa, FTAG); + mutex_exit(&spa_namespace_lock); + dp = spa_get_dsl(spa); + + dsl_pool_config_enter(dp, FTAG); + error = dump_list_strategy_one(dp, dp->dp_root_dir_obj, + DS_FIND_CHILDREN | DS_FIND_SERIALIZE, dls); + dsl_pool_config_exit(dp, FTAG); + + mutex_enter(&spa_namespace_lock); + spa_close(spa, FTAG); + } + mutex_exit(&spa_namespace_lock); + + return (error); +} + +void +dump_list_strategy(void *arg) +{ + dls_t *dls = arg; + zfs_pipe_record_t zpr; + ssize_t resid; + + bzero(&zpr, sizeof (zfs_pipe_record_t)); + + zpr.zpr_err = (uint8_t) dump_list_strategy_impl(dls); + + (void) vn_rdwr(UIO_WRITE, dls->dls_vp, (caddr_t) &zpr, + sizeof (uint64_t), 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, + CRED(), &resid); + + areleasef(dls->dls_fd, dls->dls_fip); + if (dls->dls_fsname) + spa_strfree((char *)dls->dls_fsname); + kmem_free(dls, sizeof (dls_t)); +} + +static int +zfs_stable_ioc_zfs_list(const char *fsname, nvlist_t *innvl, + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) +{ + dsl_pool_t *dp = NULL; + int fd; + file_t *fp; + nvlist_t *type = NULL; + dls_t *dls; + dls_flag_t dls_flags = 0; + uint64_t depth = DS_FIND_MAX_DEPTH; + boolean_t name_specified = fsname != NULL && fsname[0] != '\0'; + int error; + + error = nvlist_lookup_int32(opts, "fd", &fd); + if (error != 0) + return (SET_ERROR(EINVAL)); + + fp = getf(fd); + if (fp == NULL) { + return (SET_ERROR(EBADF)); + } + + if (nvlist_lookup_nvlist(opts, "type", &type) == 0 && + !nvlist_empty(type)) { + if (nvlist_exists(type, "all")) + dls_flags |= DLS_TRAVERSE_ALL; + else { + if (nvlist_exists(type, "bookmark")) + dls_flags |= DLS_TRAVERSE_BOOKMARK; + if (nvlist_exists(type, "filesystem")) + dls_flags |= DLS_TRAVERSE_FILESYSTEM; + if (nvlist_exists(type, "snap")) + dls_flags |= DLS_TRAVERSE_SNAPSHOT; + if (nvlist_exists(type, "snapshot")) + dls_flags |= DLS_TRAVERSE_SNAPSHOT; + if (nvlist_exists(type, "volume")) + dls_flags |= DLS_TRAVERSE_VOLUME; + } + } else if (!name_specified) { + dls_flags |= DLS_TRAVERSE_FILESYSTEM; + dls_flags |= DLS_TRAVERSE_VOLUME; + } + + if (nvlist_exists(opts, "recurse")) { + dls_flags |= DLS_RECURSE; + (void) nvlist_lookup_uint64(opts, "recurse", &depth); + } else if (name_specified) { + depth = 0; + } + + /* Pass an object number when given a DSL directory name */ + if (name_specified) { + dsl_dataset_t *ds = NULL; + + error = dsl_pool_hold(fsname, FTAG, &dp); + if (error != 0) + return (error); + error = dsl_dataset_hold(dp, fsname, FTAG, &ds); + if (error != 0) { + dsl_pool_rele(dp, FTAG); + return (error); + } + + if ((strchr(fsname, '#') != NULL)) { + dls_flags |= DLS_TRAVERSE_BOOKMARK; + dls_flags &= ~DLS_RECURSE; + } else if ((strchr(fsname, '@') != NULL)) { + dls_flags |= DLS_TRAVERSE_SNAPSHOT; + dls_flags &= ~DLS_RECURSE; + /* XXX: We need a depth of 1 to reach the snapshot */ + depth = 1; + } else if (nvlist_empty(type)) { + /* Adopt sane defaults based on the DSL directory */ + objset_t *osp; + dmu_objset_from_ds(ds, &osp); + + switch (dmu_objset_type(osp)) { + case DMU_OST_ZVOL: + dls_flags |= DLS_TRAVERSE_VOLUME; + break; + case DMU_OST_ZFS: + dls_flags |= DLS_TRAVERSE_FILESYSTEM; + break; + default: + VERIFY(0); + } + } + + dsl_dataset_rele(ds, FTAG); + dsl_pool_rele(dp, FTAG); + } + + dls = kmem_alloc(sizeof (dls_t), KM_SLEEP); + dls->dls_fd = fd; + dls->dls_fip = P_FINFO(curproc); + dls->dls_vp = fp->f_vnode; + dls->dls_depth = depth; + dls->dls_flags = dls_flags; + dls->dls_fsname = (name_specified) ? spa_strdup(fsname) : NULL; + + if (!taskq_dispatch(system_taskq, dump_list_strategy, dls, TQ_SLEEP)) { + kmem_free(dls, sizeof (dls_t)); + releasef(fd); + return (SET_ERROR(ENOMEM)); + } + + return (error); +} + /* * ioctl table for stable interface. * Functions use zfs_/zpool_ prefixes to distinguish between their uses @@ -5765,6 +6187,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_TRUE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_list", + .zvec_func = zfs_stable_ioc_zfs_list, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME_OR_EMPTY, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_TRUE, +}, }; static const ssize_t zfs_stable_ioc_vec_count = @@ -5777,20 +6207,28 @@ zfs_namecheck(const char *name, zfs_ioc_namecheck_t namecheck, int error = 0; switch (namecheck) { + case POOL_NAME_OR_EMPTY: + if (name[0] == '\0') + break; case POOL_NAME: if (pool_namecheck(name, NULL, NULL) != 0) error = SET_ERROR(EINVAL); else error = pool_status_check(name, - namecheck, pool_check); + POOL_NAME, pool_check); break; + case DATASET_NAME_OR_EMPTY: + if (name[0] == '\0') + break; case DATASET_NAME: + if (name[0] == '\0') + break; if (dataset_namecheck(name, NULL, NULL) != 0) error = SET_ERROR(EINVAL); else error = pool_status_check(name, - namecheck, pool_check); + DATASET_NAME, pool_check); break; case NO_NAME: @@ -5867,7 +6305,6 @@ zfs_ioc_stable(zfs_cmd_t *zc) for (i = 0; i < zfs_stable_ioc_vec_count; i++) { if (strcmp(zfs_stable_ioc_vec[i].zvec_name, cmd) == 0) { - nvlist_t *lognv = NULL; const zfs_stable_ioc_vec_t *vec = &zfs_stable_ioc_vec[i]; nvlist_t *lognv = NULL; From 66a2da81d33bdd120056d3a08cc8a26bf3cc93e3 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Wed, 18 Mar 2015 11:50:25 -0400 Subject: [PATCH 23/40] Implement lzc_rename() Signed-off-by: Richard Yao --- include/libzfs_core.h | 3 + include/sys/dmu.h | 4 +- include/sys/dsl_dataset.h | 2 +- lib/libzfs/libzfs_dataset.c | 25 ++++---- lib/libzfs_core/libzfs_core.c | 42 ++++++++++++ module/zfs/dmu_objset.c | 2 +- module/zfs/dsl_dataset.c | 13 +++- module/zfs/zfs_ioctl.c | 117 +++++++++++++++++++++++++++------- 8 files changed, 167 insertions(+), 41 deletions(-) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index db0171d61397..9d313b7b3a39 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -55,6 +55,9 @@ int lzc_hold(nvlist_t *, int, nvlist_t **); int lzc_release(nvlist_t *, nvlist_t **); int lzc_get_holds(const char *, nvlist_t **); +int lzc_rename(const char *oldname, const char *newname, nvlist_t *opts, + char **errname); + enum lzc_send_flags { LZC_SEND_FLAG_EMBED_DATA = 1 << 0, LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1 diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 80aa2de4db94..8eab67509fb7 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -277,8 +277,8 @@ int dsl_destroy_snapshots_nvl(struct nvlist *snaps, boolean_t defer, struct nvlist *errlist); int dmu_objset_snapshot_one(const char *fsname, const char *snapname); int dmu_objset_snapshot_tmp(const char *, const char *, int); -int dmu_objset_find(char *name, int func(const char *, void *), void *arg, - int flags); +int dmu_objset_find(const char *name, int func(const char *, void *), + void *arg, int flags); void dmu_objset_byteswap(void *buf, size_t size); typedef struct dmu_buf { diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index 7ea900f7bc9c..68122bb7bd51 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -227,7 +227,7 @@ uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, uint64_t flags, dmu_tx_t *tx); int dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors); int dsl_dataset_promote(const char *name, char *conflsnap); -int dsl_dataset_rename_snapshot(const char *fsname, +int dsl_dataset_rename_snapshot(char *fsname, const char *oldsnapname, const char *newsnapname, boolean_t recursive); int dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname, minor_t cleanup_minor, const char *htag); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 66af47c496d0..c6c0cc2d9b61 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -3804,7 +3804,6 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, boolean_t force_unmount) { int ret; - zfs_cmd_t zc = {"\0"}; char *delim; prop_changelist_t *cl = NULL; zfs_handle_t *zhrp = NULL; @@ -3812,6 +3811,8 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, char parent[ZFS_MAXNAMELEN]; libzfs_handle_t *hdl = zhp->zfs_hdl; char errbuf[1024]; + char *errname; + nvlist_t *opts = NULL; /* if we have the same exact name, just return success */ if (strcmp(zhp->zfs_name, target) == 0) @@ -3930,23 +3931,19 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, goto error; } - if (ZFS_IS_VOLUME(zhp)) - zc.zc_objset_type = DMU_OST_ZVOL; - else - zc.zc_objset_type = DMU_OST_ZFS; - - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); - - zc.zc_cookie = recursive; + if (recursive) { + opts = fnvlist_alloc(); + fnvlist_add_boolean(opts, "recursive"); + } - if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { + if ((ret = lzc_rename(zhp->zfs_name, target, opts, &errname)) != 0) { /* * if it was recursive, the one that actually failed will - * be in zc.zc_name + * be in errname */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, - "cannot rename '%s'"), zc.zc_name); + "cannot rename '%s'"), errname); + strfree(errname); if (recursive && errno == EEXIST) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -3970,6 +3967,8 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, } } + if (recursive) + fnvlist_free(opts); error: if (parentname) { free(parentname); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 2a8dead1d4f9..df9c9dd16707 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -806,6 +806,48 @@ lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist) return (error); } +/* + * Rename DSL directory (i.e. filesystems, volumes, snapshots) + * + * The opts flag accepts a boolean named "recursive" to signal that the + * mountpoint property on children should be updated. + * + * The following are the valid properties in opts, all of which are booleans: + * + * "recursive" - Rename mountpoints on child DSL directories + * + * If a recursive rename is done, an error occurs and errname is initialized, a + * string will be allocated with strdup() and returned via it. The caller must + * free it with strfree(). + */ +int +lzc_rename(const char *oldname, const char *newname, nvlist_t *opts, + char **errname) +{ + nvlist_t *args, *errlist; + int error; + + if (newname == NULL || (oldname == NULL || + strlen(oldname) == 0 || strlen(newname) == 0)) + return (EINVAL); + + args = fnvlist_alloc(); + errlist = (errname != NULL) ? fnvlist_alloc() : NULL; + fnvlist_add_string(args, "newname", newname); + error = lzc_ioctl("zfs_rename", oldname, args, opts, &errlist, 0); + + if (error && errname != NULL) { + const char *name = fnvlist_lookup_string(errlist, "name"); + *errname = strdup(name); + } + + fnvlist_free(args); + if (errlist) + fnvlist_free(errlist); + + return (error); +} + /* * List DSL directory/directories * diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 512ebe15b176..6329c9d59357 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -1973,7 +1973,7 @@ dmu_objset_find_impl(spa_t *spa, const char *name, * See comment above dmu_objset_find_impl(). */ int -dmu_objset_find(char *name, int func(const char *, void *), void *arg, +dmu_objset_find(const char *name, int func(const char *, void *), void *arg, int flags) { spa_t *spa; diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 3dcaed0e873a..e9c60d3d8cd7 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -1779,7 +1779,7 @@ dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap) } typedef struct dsl_dataset_rename_snapshot_arg { - const char *ddrsa_fsname; + char *ddrsa_fsname; const char *ddrsa_oldsnapname; const char *ddrsa_newsnapname; boolean_t ddrsa_recursive; @@ -1798,6 +1798,7 @@ dsl_dataset_rename_snapshot_check_impl(dsl_dataset_t *hds, boolean_t unused, error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_oldsnapname, &val); /* ignore nonexistent snapshots */ if (error != 0 || error != ENOENT) { + dsl_dir_name(hds->ds_dir, ddrsa->ddrsa_fsname); return (error); } @@ -1813,6 +1814,9 @@ dsl_dataset_rename_snapshot_check_impl(dsl_dataset_t *hds, boolean_t unused, strlen(ddrsa->ddrsa_newsnapname) >= MAXNAMELEN) error = SET_ERROR(ENAMETOOLONG); + if (error) + dsl_dir_name(hds->ds_dir, ddrsa->ddrsa_fsname); + return (error); } @@ -1897,8 +1901,13 @@ dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx) dsl_dataset_rele(hds, FTAG); } +/* + * On error, fsname is updated with the name of the filesystem where the error + * occurred. + */ + int -dsl_dataset_rename_snapshot(const char *fsname, +dsl_dataset_rename_snapshot(char *fsname, const char *oldsnapname, const char *newsnapname, boolean_t recursive) { #ifdef _KERNEL diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 00a9286c2e76..6091a2b179a0 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -391,6 +391,30 @@ zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) return (SET_ERROR(ENOENT)); } +/* + * Policy for dataset rename operations. Requires rename permission and mount + * permission on dataset. Also requires create and mount permission on the new + * parent. Must be visible in the local zone. + */ +/* ARGSUSED */ +static int +zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) +{ + char *newname; + int error; + + if (INGLOBALZONE(curproc) || + zone_dataset_visible(zc->zc_name, NULL)) + return (0); + + error = nvlist_lookup_string(innvl, "newname", &newname); + if (error) + return (error); + + + return (zfs_secpolicy_rename_perms(zc->zc_name, newname, cr)); +} + static int zfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr) { @@ -889,7 +913,8 @@ zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) +zfs_secpolicy_rename_legacy(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) { return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); } @@ -2381,6 +2406,7 @@ zfs_ioc_list_next(zfs_cmd_t *zc, boolean_t snapshot) zl.zl_name = zc->zc_name; zl.zl_objset_stats = &zc->zc_objset_stats; zl.zl_cookie = zc->zc_cookie; + zl.zl_nvlist = NULL; if (snapshot) { zl.zl_obj = zc->zc_obj; @@ -3805,35 +3831,35 @@ recursive_unmount(const char *fsname, void *arg) return (error); } -/* - * inputs: - * zc_name old name of dataset - * zc_value new name of dataset - * zc_cookie recursive flag (only valid for snapshots) - * - * outputs: none - */ +/* Note that oldname is updated on failure when recursive */ static int -zfs_ioc_rename(zfs_cmd_t *zc) +zfs_rename(char *oldname, const char *newname, boolean_t recursive) { - boolean_t recursive = zc->zc_cookie & 1; char *at; - zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; - if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || - strchr(zc->zc_value, '%')) + /* Caller must NULL terminate newname. */ + if (dataset_namecheck(newname, NULL, NULL) != 0 || + strchr(newname, '%')) return (SET_ERROR(EINVAL)); - at = strchr(zc->zc_name, '@'); + at = strchr(oldname, '@'); if (at != NULL) { /* snaps must be in same fs */ int error; + objset_t *os; + dmu_objset_type_t ostype; - if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) + if (strncmp(oldname, newname, at - oldname + 1)) return (SET_ERROR(EXDEV)); *at = '\0'; - if (zc->zc_objset_type == DMU_OST_ZFS) { - error = dmu_objset_find(zc->zc_name, + + if ((error = dmu_objset_hold(oldname, FTAG, &os)) != 0) + return (error); + ostype = dmu_objset_type(os); + dmu_objset_rele(os, FTAG); + + if (ostype == DMU_OST_ZFS) { + error = dmu_objset_find(oldname, recursive_unmount, at + 1, recursive ? DS_FIND_CHILDREN : 0); if (error != 0) { @@ -3841,14 +3867,31 @@ zfs_ioc_rename(zfs_cmd_t *zc) return (error); } } - error = dsl_dataset_rename_snapshot(zc->zc_name, - at + 1, strchr(zc->zc_value, '@') + 1, recursive); + error = dsl_dataset_rename_snapshot(oldname, + at + 1, strchr(newname, '@') + 1, recursive); *at = '@'; return (error); } else { - return (dsl_dir_rename(zc->zc_name, zc->zc_value)); + return (dsl_dir_rename(oldname, newname)); } + +} + +/* + * inputs: + * zc_name old name of dataset + * zc_value new name of dataset + * zc_cookie recursive flag (only valid for snapshots) + * + * outputs: + * zc_name name of dataset which failed (only on failure if recursive) + */ +static int +zfs_ioc_rename(zfs_cmd_t *zc) +{ + zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; + return (zfs_rename(zc->zc_name, zc->zc_value, (zc->zc_cookie & 1))); } static int @@ -5599,6 +5642,28 @@ zfs_stable_ioc_set_props(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, return (error); } +static int +zfs_stable_ioc_zfs_rename(const char *oldname, nvlist_t *innvl, + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) +{ + char *newname; + char buf[ZFS_MAXNAMELEN]; + boolean_t recursive; + int error; + + error = nvlist_lookup_string(innvl, "newname", &newname); + if (error) + return (error); + (void) strlcpy(buf, oldname, sizeof (buf)); + + recursive = nvlist_exists(opts, "recursive"); + error = zfs_rename(buf, newname, recursive); + if (error && recursive && strchr(oldname, '@')) + fnvlist_add_string(outnvl, "name", buf); + + return (error); +} + int pool_status_check(const char *name, zfs_ioc_namecheck_t type, zfs_ioc_poolcheck_t check); @@ -6195,6 +6260,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_FALSE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_rename", + .zvec_func = zfs_stable_ioc_zfs_rename, + .zvec_secpolicy = zfs_secpolicy_rename, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_TRUE, + .zvec_allow_log = B_TRUE, +}, }; static const ssize_t zfs_stable_ioc_vec_count = @@ -6654,7 +6727,7 @@ zfs_ioctl_init(void) zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy, zfs_secpolicy_destroy); zfs_ioctl_register_dataset_modify(ZFS_IOC_RENAME, zfs_ioc_rename, - zfs_secpolicy_rename); + zfs_secpolicy_rename_legacy); zfs_ioctl_register_dataset_modify(ZFS_IOC_RECV, zfs_ioc_recv, zfs_secpolicy_recv); zfs_ioctl_register_dataset_modify(ZFS_IOC_PROMOTE, zfs_ioc_promote, From a9d29c032e0cc707bdd49b09421d8eaf8b98e4e2 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 19 Mar 2015 11:07:23 -0400 Subject: [PATCH 24/40] Implement lzc_inherit() Signed-off-by: Richard Yao --- include/libzfs_core.h | 1 + lib/libzfs/libzfs_dataset.c | 28 +++++++---- lib/libzfs_core/libzfs_core.c | 26 ++++++++++ module/zfs/zfs_ioctl.c | 94 +++++++++++++++++++++++++++-------- 4 files changed, 118 insertions(+), 31 deletions(-) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 9d313b7b3a39..97cf8e3a0165 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -55,6 +55,7 @@ int lzc_hold(nvlist_t *, int, nvlist_t **); int lzc_release(nvlist_t *, nvlist_t **); int lzc_get_holds(const char *, nvlist_t **); +int lzc_inherit(const char *fsname, const char *propname, nvlist_t *opts); int lzc_rename(const char *oldname, const char *newname, nvlist_t *opts, char **errname); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index c6c0cc2d9b61..64e300caa17f 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1652,7 +1652,7 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) int zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) { - zfs_cmd_t zc = {"\0"}; + nvlist_t *opts = NULL; int ret; prop_changelist_t *cl; libzfs_handle_t *hdl = zhp->zfs_hdl; @@ -1662,8 +1662,8 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s'"), propname, zhp->zfs_name); - zc.zc_cookie = received; if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { + ret = 0; /* * For user properties, the amount of work we have to do is very * small, so just do it here. @@ -1674,13 +1674,15 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); + if (received) { + opts = fnvlist_alloc(); + fnvlist_add_boolean(opts, "received"); + } - if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) - return (zfs_standard_error(hdl, errno, errbuf)); + if (ret == 0 && lzc_inherit(zhp->zfs_name, propname, opts) != 0) + ret = zfs_standard_error(hdl, errno, errbuf); - return (0); + goto out; } /* @@ -1702,8 +1704,6 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) * Normalize the name, to get rid of shorthand abbreviations. */ propname = zfs_prop_to_name(prop); - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID && zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { @@ -1729,7 +1729,12 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) if ((ret = changelist_prefix(cl)) != 0) goto error; - if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { + if (received) { + opts = fnvlist_alloc(); + fnvlist_add_boolean(opts, "received"); + } + + if ((ret = lzc_inherit(zhp->zfs_name, propname, opts)) != 0) { return (zfs_standard_error(hdl, errno, errbuf)); } else { @@ -1753,6 +1758,9 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) error: changelist_free(cl); +out: + if (opts) + fnvlist_free(opts); return (ret); } diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index df9c9dd16707..a2bb96c7155b 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -806,6 +806,32 @@ lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist) return (error); } +/* + * Resets a property on a DSL directory (i.e. filesystems, volumes, snapshots) + * to its original value. + * + * The following are the valid properties in opts, all of which are booleans: + * + * "received" - resets property value to from `zfs recv` if it set a value + */ +int +lzc_inherit(const char *fsname, const char *propname, nvlist_t *opts) +{ + nvlist_t *args; + int error; + + if (fsname == NULL || (propname == NULL || + strlen(fsname) == 0 || strlen(propname) == 0)) + return (EINVAL); + + args = fnvlist_alloc(); + fnvlist_add_string(args, "prop", propname); + error = lzc_ioctl("zfs_inherit", fsname, args, opts, NULL, 0); + fnvlist_free(args); + + return (error); +} + /* * Rename DSL directory (i.e. filesystems, volumes, snapshots) * diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 6091a2b179a0..19aa208bbf95 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -1178,22 +1178,43 @@ zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) /* ARGSUSED */ static int -zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, +zfs_secpolicy_inherit_prop_impl(const char *fsname, const char *propname, cred_t *cr) { - zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); + zfs_prop_t prop = zfs_name_to_prop(propname); if (prop == ZPROP_INVAL) { - if (!zfs_prop_user(zc->zc_value)) + if (!zfs_prop_user(propname)) return (SET_ERROR(EINVAL)); - return (zfs_secpolicy_write_perms(zc->zc_name, + return (zfs_secpolicy_write_perms(fsname, ZFS_DELEG_PERM_USERPROP, cr)); } else { - return (zfs_secpolicy_setprop(zc->zc_name, prop, + return (zfs_secpolicy_setprop(fsname, prop, NULL, cr)); } } +/* ARGSUSED */ +static int +zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, + cred_t *cr) +{ + char *propname; + int error; + + if ((error = nvlist_lookup_string(innvl, "prop", &propname))) + return (error); + + return (zfs_secpolicy_inherit_prop_impl(zc->zc_name, propname, cr)); +} +/* ARGSUSED */ +static int +zfs_secpolicy_inherit_prop_legacy(zfs_cmd_t *zc, nvlist_t *innvl, + nvlist_t *opts, cred_t *cr) +{ + return (zfs_secpolicy_inherit_prop_impl(zc->zc_name, zc->zc_value, + cr)); +} static int zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, nvlist_t *opts, cred_t *cr) @@ -2916,20 +2937,10 @@ zfs_ioc_set_prop(zfs_cmd_t *zc) return (error); } -/* - * inputs: - * zc_name name of filesystem - * zc_value name of property to inherit - * zc_cookie revert to received value if TRUE - * - * outputs: none - */ static int -zfs_ioc_inherit_prop(zfs_cmd_t *zc) +zfs_inherit_prop(const char *fsname, const char *propname, boolean_t received) { - const char *propname = zc->zc_value; zfs_prop_t prop = zfs_name_to_prop(propname); - boolean_t received = zc->zc_cookie; zprop_source_t source = (received ? ZPROP_SRC_NONE /* revert to received value, if any */ : ZPROP_SRC_INHERITED); /* explicitly inherit */ @@ -2972,7 +2983,7 @@ zfs_ioc_inherit_prop(zfs_cmd_t *zc) } pair = nvlist_next_nvpair(dummy, NULL); - err = zfs_prop_set_special(zc->zc_name, source, pair); + err = zfs_prop_set_special(fsname, source, pair); nvlist_free(dummy); if (err != -1) return (err); /* special property already handled */ @@ -2988,7 +2999,22 @@ zfs_ioc_inherit_prop(zfs_cmd_t *zc) } /* property name has been validated by zfs_secpolicy_inherit_prop() */ - return (dsl_prop_inherit(zc->zc_name, zc->zc_value, source)); + return (dsl_prop_inherit(fsname, propname, source)); +} + +/* + * inputs: + * zc_name name of filesystem + * zc_value name of property to inherit + * zc_cookie revert to received value if TRUE + * + * outputs: none + */ +static int +zfs_ioc_inherit_prop(zfs_cmd_t *zc) +{ + return (zfs_inherit_prop(zc->zc_name, zc->zc_value, + !!(zc->zc_cookie))); } static int @@ -4105,8 +4131,8 @@ zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist) (void) strcpy(zc->zc_value, nvpair_name(pair)); if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 || - (err = zfs_secpolicy_inherit_prop(zc, NULL, NULL, CRED())) - != 0) { + (err = zfs_secpolicy_inherit_prop_legacy(zc, NULL, NULL, + CRED())) != 0) { VERIFY(nvlist_remove_nvpair(props, pair) == 0); VERIFY(nvlist_add_int32(errors, zc->zc_value, err) == 0); @@ -5642,6 +5668,24 @@ zfs_stable_ioc_set_props(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl, return (error); } + +/* + * XXX: Before we stabilize this, we should consider making it accept a list of + * things to inherit + */ +static int +zfs_stable_ioc_zfs_inherit(const char *fsname, nvlist_t *innvl, + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) +{ + char *propname; + int error; + + if ((error = nvlist_lookup_string(innvl, "prop", &propname))) + return (error); + + return (zfs_inherit_prop(fsname, propname, + nvlist_exists(opts, "received"))); +} static int zfs_stable_ioc_zfs_rename(const char *oldname, nvlist_t *innvl, nvlist_t *outnvl, nvlist_t *opts, uint64_t version) @@ -6268,6 +6312,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_TRUE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_inherit", + .zvec_func = zfs_stable_ioc_zfs_inherit, + .zvec_secpolicy = zfs_secpolicy_inherit_prop, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_TRUE, +}, }; static const ssize_t zfs_stable_ioc_vec_count = @@ -6733,7 +6785,7 @@ zfs_ioctl_init(void) zfs_ioctl_register_dataset_modify(ZFS_IOC_PROMOTE, zfs_ioc_promote, zfs_secpolicy_promote); zfs_ioctl_register_dataset_modify(ZFS_IOC_INHERIT_PROP, - zfs_ioc_inherit_prop, zfs_secpolicy_inherit_prop); + zfs_ioc_inherit_prop, zfs_secpolicy_inherit_prop_legacy); zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_FSACL, zfs_ioc_set_fsacl, zfs_secpolicy_set_fsacl); From 4d9a63db9671b7fbe0ead265a64221479eb00538 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 27 Mar 2015 10:19:02 -0400 Subject: [PATCH 25/40] Implement lzc_destroy_one() This was originally intended to be `lzc_destroy()`, but recent versions of the Linux kernel appear to have removed the information we need to unmount datasets from the kernel driver without resorting to symbol table hacks. Consequently, unmounting requires doing upcalls to userland and error handling becomes easier if we delegate unmounting to the userland caller. Signed-off-by: Richard Yao --- include/libzfs_core.h | 1 + lib/libzfs/libzfs_dataset.c | 20 +++++------ lib/libzfs/libzfs_sendrecv.c | 19 ++++++---- lib/libzfs_core/libzfs_core.c | 28 +++++++++++++++ module/zfs/zfs_ioctl.c | 66 +++++++++++++++++++++++++++-------- 5 files changed, 102 insertions(+), 32 deletions(-) diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 97cf8e3a0165..4e7242688706 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -44,6 +44,7 @@ int lzc_create(const char *, dmu_objset_type_t, nvlist_t *); int lzc_clone(const char *, const char *, nvlist_t *); int lzc_promote(const char *, nvlist_t *); int lzc_set_props(const char *, nvlist_t *, nvlist_t *, nvlist_t **); +int lzc_destroy_one(const char *, nvlist_t *); int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); int lzc_bookmark(nvlist_t *, nvlist_t **); int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 64e300caa17f..a1f9967da578 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -3284,7 +3284,8 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, int zfs_destroy(zfs_handle_t *zhp, boolean_t defer) { - zfs_cmd_t zc = {"\0"}; + nvlist_t *opts = NULL; + int ret = 0; if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { nvlist_t *nv = fnvlist_alloc(); @@ -3299,17 +3300,16 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) return (0); } - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - - if (ZFS_IS_VOLUME(zhp)) { - zc.zc_objset_type = DMU_OST_ZVOL; - } else { - zc.zc_objset_type = DMU_OST_ZFS; + if (defer) { + opts = fnvlist_alloc(); + fnvlist_add_boolean(opts, "defer"); } - zc.zc_defer_destroy = defer; - if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && - errno != ENOENT) { + ret = lzc_destroy_one(zhp->zfs_name, opts); + if (defer) + fnvlist_free(opts); + + if (ret != 0 && errno != ENOENT) { return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), zhp->zfs_name)); diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 8d1a210947a2..eb69c13b2610 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -1862,7 +1862,7 @@ static int recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, char *newname, recvflags_t *flags) { - zfs_cmd_t zc = {"\0"}; + nvlist_t *opts = NULL; int err = 0; prop_changelist_t *clp; zfs_handle_t *zhp; @@ -1885,17 +1885,22 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, if (err) return (err); - zc.zc_objset_type = DMU_OST_ZFS; - zc.zc_defer_destroy = defer; - (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); + if (defer) { + opts = fnvlist_alloc(); + fnvlist_add_boolean(opts, "defer"); + } if (flags->verbose) - (void) printf("attempting destroy %s\n", zc.zc_name); - err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); + (void) printf("attempting destroy %s\n", name); + err = lzc_destroy_one(name, opts); + + if (defer) + fnvlist_free(opts); + if (err == 0) { if (flags->verbose) (void) printf("success\n"); - changelist_remove(clp, zc.zc_name); + changelist_remove(clp, name); } (void) changelist_postfix(clp); diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index a2bb96c7155b..0c01cc27bf01 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -832,6 +832,34 @@ lzc_inherit(const char *fsname, const char *propname, nvlist_t *opts) return (error); } +/* + * Destroys a DSL directory that is either a filesystems or a volume. + * Destroying snapshots and bookmarks is not currently supported. Call + * lzc_destroy_snaps and lzc_destroy_bookmarks for those respectively. + * + * The only currently valid property is the boolean "defer". It makes + * destruction asynchronous such that the only error code back is if we try to + * destroy something that does not exist. The caller must unmount the dataset + * before calling this. Otherwise, it will fail. + */ + +int +lzc_destroy_one(const char *fsname, nvlist_t *opts) +{ + nvlist_t *args; + int error; + + if (fsname == NULL || + strlen(fsname) == 0) + return (EINVAL); + + args = fnvlist_alloc(); + error = lzc_ioctl("zfs_destroy", fsname, args, opts, NULL, 0); + fnvlist_free(args); + + return (error); +} + /* * Rename DSL directory (i.e. filesystems, volumes, snapshots) * diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 19aa208bbf95..f40cffd8d806 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -3784,6 +3784,39 @@ zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl, return (error); } + +/* If ostype is DMU_OST_NONE, we perform a lookup. */ +static int +zfs_destroy_impl(const char *fsname, dmu_objset_type_t ostype, + boolean_t defer_destroy) +{ + int err; + + if (ostype == DMU_OST_NONE) { + objset_t *os; + + err = dmu_objset_hold(fsname, FTAG, &os); + if (err != 0) + return (err); + ostype = dmu_objset_type(os); + dmu_objset_rele(os, FTAG); + } + + if (ostype == DMU_OST_ZFS) { + err = zfs_unmount_snap(fsname); + if (err != 0) + return (err); + } + + if (strchr(fsname, '@')) + err = dsl_destroy_snapshot(fsname, defer_destroy); + else + err = dsl_destroy_head(fsname); + if (ostype == DMU_OST_ZVOL && err == 0) + (void) zvol_remove_minor(fsname); + return (err); +} + /* * inputs: * zc_name name of dataset to destroy @@ -3795,21 +3828,8 @@ zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl, static int zfs_ioc_destroy(zfs_cmd_t *zc) { - int err; - - if (zc->zc_objset_type == DMU_OST_ZFS) { - err = zfs_unmount_snap(zc->zc_name); - if (err != 0) - return (err); - } - - 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); + return (zfs_destroy_impl(zc->zc_name, zc->zc_objset_type, + zc->zc_defer_destroy)); } /* @@ -6154,6 +6174,14 @@ zfs_stable_ioc_zfs_list(const char *fsname, nvlist_t *innvl, return (error); } +static int +zfs_stable_ioc_zfs_destroy(const char *fsname, nvlist_t *innvl, + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) +{ + return (zfs_destroy_impl(fsname, DMU_OST_NONE, + nvlist_exists(opts, "defer"))); +} + /* * ioctl table for stable interface. * Functions use zfs_/zpool_ prefixes to distinguish between their uses @@ -6320,6 +6348,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_FALSE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_destroy", + .zvec_func = zfs_stable_ioc_zfs_destroy, + .zvec_secpolicy = zfs_secpolicy_destroy, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_TRUE, +}, }; static const ssize_t zfs_stable_ioc_vec_count = From 57ea161bcc5c7c38e3c07784c33638d13c50117f Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 26 May 2015 12:40:25 -0400 Subject: [PATCH 26/40] Implement lzc_exists in stable API Signed-off-by: Richard Yao --- lib/libzfs_core/libzfs_core.c | 9 +-------- module/zfs/zfs_ioctl.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 0c01cc27bf01..3d97619f1282 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -365,14 +365,7 @@ lzc_snaprange_space(const char *firstsnap, const char *lastsnap, boolean_t lzc_exists(const char *dataset) { - /* - * The objset_stats ioctl is still legacy, so we need to construct our - * own zfs_cmd_t rather than using zfsc_ioctl(). - */ - zfs_cmd_t zc = {"\0"}; - - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0); + return (lzc_ioctl("zfs_exists", dataset, NULL, NULL, NULL, 0) == 0); } /* diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index f40cffd8d806..bb2e54ef5a12 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -6182,6 +6182,20 @@ zfs_stable_ioc_zfs_destroy(const char *fsname, nvlist_t *innvl, nvlist_exists(opts, "defer"))); } +static int +zfs_stable_ioc_zfs_exists(const char *fsname, nvlist_t *innvl, + nvlist_t *outnvl, nvlist_t *opts, uint64_t version) +{ + objset_t *os; + int error; + + error = dmu_objset_hold(fsname, FTAG, &os); + if (error == 0) + dmu_objset_rele(os, FTAG); + + return (error); +} + /* * ioctl table for stable interface. * Functions use zfs_/zpool_ prefixes to distinguish between their uses @@ -6356,6 +6370,14 @@ static const zfs_stable_ioc_vec_t zfs_stable_ioc_vec[] = { .zvec_smush_outnvlist = B_FALSE, .zvec_allow_log = B_TRUE, }, +{ .zvec_name = "zfs_exists", + .zvec_func = zfs_stable_ioc_zfs_exists, + .zvec_secpolicy = zfs_secpolicy_read, + .zvec_namecheck = DATASET_NAME, + .zvec_pool_check = POOL_CHECK_SUSPENDED, + .zvec_smush_outnvlist = B_FALSE, + .zvec_allow_log = B_FALSE, +}, }; static const ssize_t zfs_stable_ioc_vec_count = From b23828a177792bd3161471a0aa30cbf810f3a7a8 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 26 Feb 2015 17:49:03 +0200 Subject: [PATCH 27/40] Add man pages for libzfs_core Signed-off-by: Richard Yao --- configure.ac | 1 + man/Makefile.am | 2 +- man/man3/Makefile.am | 30 +++ man/man3/libzfs_core.h.3 | 116 ++++++++++ man/man3/libzfs_core_fini.3 | 1 + man/man3/libzfs_core_init.3 | 65 ++++++ man/man3/lzc_bookmark.3 | 159 +++++++++++++ man/man3/lzc_clone.3 | 154 +++++++++++++ man/man3/lzc_create.3 | 141 ++++++++++++ man/man3/lzc_destroy_bookmarks.3 | 133 +++++++++++ man/man3/lzc_destroy_one.3 | 149 ++++++++++++ man/man3/lzc_destroy_snaps.3 | 159 +++++++++++++ man/man3/lzc_exists.3 | 68 ++++++ man/man3/lzc_get_bookmarks.3 | 165 ++++++++++++++ man/man3/lzc_get_holds.3 | 129 +++++++++++ man/man3/lzc_hold.3 | 182 +++++++++++++++ man/man3/lzc_inherit.3 | 145 ++++++++++++ man/man3/lzc_list.3 | 374 +++++++++++++++++++++++++++++++ man/man3/lzc_promote.3 | 139 ++++++++++++ man/man3/lzc_receive.3 | 237 ++++++++++++++++++++ man/man3/lzc_release.3 | 1 + man/man3/lzc_rename.3 | 132 +++++++++++ man/man3/lzc_rollback.3 | 143 ++++++++++++ man/man3/lzc_send.3 | 220 ++++++++++++++++++ man/man3/lzc_send_progress.3 | 111 +++++++++ man/man3/lzc_send_space.3 | 127 +++++++++++ man/man3/lzc_set_props.3 | 212 ++++++++++++++++++ man/man3/lzc_snaprange_space.3 | 133 +++++++++++ man/man3/lzc_snapshot.3 | 174 ++++++++++++++ rpm/generic/zfs.spec.in | 3 +- 30 files changed, 3803 insertions(+), 2 deletions(-) create mode 100644 man/man3/Makefile.am create mode 100644 man/man3/libzfs_core.h.3 create mode 100644 man/man3/libzfs_core_fini.3 create mode 100644 man/man3/libzfs_core_init.3 create mode 100644 man/man3/lzc_bookmark.3 create mode 100644 man/man3/lzc_clone.3 create mode 100644 man/man3/lzc_create.3 create mode 100644 man/man3/lzc_destroy_bookmarks.3 create mode 100644 man/man3/lzc_destroy_one.3 create mode 100644 man/man3/lzc_destroy_snaps.3 create mode 100644 man/man3/lzc_exists.3 create mode 100644 man/man3/lzc_get_bookmarks.3 create mode 100644 man/man3/lzc_get_holds.3 create mode 100644 man/man3/lzc_hold.3 create mode 100644 man/man3/lzc_inherit.3 create mode 100644 man/man3/lzc_list.3 create mode 100644 man/man3/lzc_promote.3 create mode 100644 man/man3/lzc_receive.3 create mode 100644 man/man3/lzc_release.3 create mode 100644 man/man3/lzc_rename.3 create mode 100644 man/man3/lzc_rollback.3 create mode 100644 man/man3/lzc_send.3 create mode 100644 man/man3/lzc_send_progress.3 create mode 100644 man/man3/lzc_send_space.3 create mode 100644 man/man3/lzc_set_props.3 create mode 100644 man/man3/lzc_snaprange_space.3 create mode 100644 man/man3/lzc_snapshot.3 diff --git a/configure.ac b/configure.ac index 9907857e2e12..b57bc1002b18 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,7 @@ AC_CONFIG_FILES([ etc/modules-load.d/Makefile man/Makefile man/man1/Makefile + man/man3/Makefile man/man5/Makefile man/man8/Makefile lib/Makefile diff --git a/man/Makefile.am b/man/Makefile.am index 841cb9c4e6a0..c6430c419a6b 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -1 +1 @@ -SUBDIRS = man1 man5 man8 +SUBDIRS = man1 man3 man5 man8 diff --git a/man/man3/Makefile.am b/man/man3/Makefile.am new file mode 100644 index 000000000000..1cb8b403dc2a --- /dev/null +++ b/man/man3/Makefile.am @@ -0,0 +1,30 @@ +dist_man_MANS = \ + libzfs_core_fini.3 \ + libzfs_core.h.3 \ + libzfs_core_init.3 \ + lzc_bookmark.3 \ + lzc_clone.3 \ + lzc_create.3 \ + lzc_destroy_bookmarks.3 \ + lzc_destroy_one.3 \ + lzc_destroy_snaps.3 \ + lzc_exists.3 \ + lzc_get_bookmarks.3 \ + lzc_get_holds.3 \ + lzc_hold.3 \ + lzc_inherit.3 \ + lzc_list.3 \ + lzc_promote.3 \ + lzc_receive.3 \ + lzc_rename.3 \ + lzc_release.3 \ + lzc_rollback.3 \ + lzc_send.3 \ + lzc_send_progress.3 \ + lzc_send_space.3 \ + lzc_set_props.3 \ + lzc_snaprange_space.3 \ + lzc_snapshot.3 + +install-data-local: + $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man3" diff --git a/man/man3/libzfs_core.h.3 b/man/man3/libzfs_core.h.3 new file mode 100644 index 000000000000..f126bbd451b7 --- /dev/null +++ b/man/man3/libzfs_core.h.3 @@ -0,0 +1,116 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH libzfs_core.h 3 "2015 JUL 3" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. The location of +the header might vary on different systems. Compilation with GCC on Linux +systems requires the addition of -I/usr/include/libspl -I/usr/include/libzfs to +GCC's parameters to include the proper headers. + +.SH NAME +libzfs_core.h \- Stable OpenZFS Management C API + +.SH SYNOPSIS +#include + +.SH DESCRIPTION +.LP +The +.IR +header shall define the following function prototype headers: +.sp +.RS 4 +.nf + +\fBint\fR \fBlibzfs_core_init\fR(\fBvoid\fR); +.p +\fBvoid\fR \fBlibzfs_core_fini\fR(\fBvoid\fR); +.sp +\fBint\fR \fBlzc_list\fR(\fBconst char *\fR\fIname\fR, \fBnvlist_t *\fR\fIopts\fR) +.p +\fBint\fR \fBlzc_snapshot\fR(\fBnvlist_t *\fR\fIsnaps\fR, \fBnvlist_t *\fR\fIprops\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.p +\fBint\fR \fBlzc_rollback\fR(\fBconst char *\fR\fIfsname\fR, \fBchar *\fR\fIsnapnamebuf\fR, \fBint\fR \fIsnapnamelen\fR); +.p +\fBint\fR \fBlzc_create\fR(\fBconst char *\fR\fIfsname\fR, \fBdmu_objset_type_t\fR \fItype\fR, \fBnvlist_t *\fR\fIprops\fR); +.p +\fBint\fR \fBlzc_clone\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR \fIorigin\fR, \fBnvlist_t *\fR\fIprops\fR); +.p +\fBint\fR \fBlzc_promote\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIopts\fR); +.p +\fBint\fR \fBlzc_set_props\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t*\fR\fIprops\fR, \fBnvlist_t *\fR\fIopts\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.p +\fBint\fR \fBlzc_destroy_one\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIopts\fR); +.p +\fBint\fR \fBlzc_destroy_snaps\fR(\fBnvlist_t *\fR\fIsnaps\fR, \fBboolean_t\fR \fIdefer\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.p +\fBint\fR \fBlzc_bookmark\fR(\fBnvlist_t *\fR\fIbookmarks\fR, \fBnvlist_t +.p +\fBint\fR \fBlzc_get_bookmarks\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIprops\fR, \fBnvlist_t **\fR\fIbmarks\fR); +.p +\fBint\fR \fBlzc_destroy_bookmarks\fR(\fBnvlist_t *\fR\fIbmarks\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.sp +\fBint\fR \fBlzc_snaprange_space\fR(\fBconst char *\fR\fIfirstsnap\fR, \fBconst char *\fR\fIlastsnap\fR, \fBuint64_t *\fR\fIusedp\fR); +.sp +\fBint\fR \fBlzc_hold\fR(\fBnvlist_t *\fR\fIholds\fR, \fBint\fR \fIcleanup_fd\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.p +\fBint\fR \fBlzc_release\fR(\fBnvlist_t *\fR\fIholds\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.p +\fBint\fR \fBlzc_get_holds\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t **\fR\fIholdsp\fR); +.sp +\fBint\fR \fBlzc_inherit\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR fIpropname\fR, \fBnvlist_t *\fR\fIopts\fR); +.p +\fBint\fR \fBlzc_rename\fR(\fBconst char *\fR\fIoldname\fR, \fBchar *\fR\fInewname\fR, \fBnvlist_t *\fR\fIopts\fR, \fBchar **\fR\fIerrname\fR); +.sp +\fBint\fR \fBlzc_send\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char *\fR\fIfrom\fR, \fBint\fR \fIfd\fR, \fBenum lzc_send_flags\fR \fIflags); +.p +\fBint\fR \fBlzc_receive\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t *\fR\fIprops\fR, \fBconst char *\fR\fIorigin\fR, \fBboolean_t\fR \fIforce\fR, \fBint\fR \fIfd\fR); +.p +\fBint\fR \fBlzc_send_space\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char *\fR\fIfrom\fR, \fBuint64_t *\fR\fIspacep\fR); +.p +\fBint\fR \fBlzc_send_progress\fR(\fBconst char *\fR\fIsnapname\fR, \fBint\fR \fIfd\fR, \fBuint64_t *\fR\fIbytesp\fR); +.sp +\fBboolean_t\fR \fBlzc_exists\fR(\fBconst char *\fR\fIdataset\fR); + +.fi \fR +.P +.RE +.P +The +.IR +header shall define the following type for lzc_send: +.sp +.RS 4 +.nf +\fB + +enum lzc_send_flags { + LZC_SEND_FLAG_EMBED_DATA = 1 << 0 +}; +.fi \fR +.SH "NOTES" +.LP +The above functions have their own man pages in section 3 of the system manual. diff --git a/man/man3/libzfs_core_fini.3 b/man/man3/libzfs_core_fini.3 new file mode 100644 index 000000000000..e966d881eea0 --- /dev/null +++ b/man/man3/libzfs_core_fini.3 @@ -0,0 +1 @@ +.so man3/libzfs_core_init.3 diff --git a/man/man3/libzfs_core_init.3 b/man/man3/libzfs_core_init.3 new file mode 100644 index 000000000000..0c5ce4a18ae2 --- /dev/null +++ b/man/man3/libzfs_core_init.3 @@ -0,0 +1,65 @@ +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH libzfs_core_init 3 "2015 JUL 3" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlibzfs_core_init\fR(\fBvoid\fR); +.sp +\fBvoid\fR \fBlibzfs_core_fini\fR(\fBvoid\fR); + +.SH NAME +libzfs_core_init, libzfs_core_fini \- Initialize and deinitialize libzfs_core library. + +.SH DESCRIPTION +.LP +The +\fBlibzfs_core_init\fR() +function is a singleton constructor for the libzfs_core library. It should be called once at program initialization. Multiple calls to +\fBlibzfs_core_init\fR() +are fine provided that they be matched by an equal number of alls to the +\fBlibzfs_core_fini\fR() +function. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion of the \fBlibzfs_core_init\fR() function, 0 is returned and a file descriptor is open for /dev/zfs. Otherwise, an error is returned. +.sp +The \fBlibzfs_core_fini\fR() function returns no value and does not fail. +.BR +.SH ERRORS +.sp +.LP +The \fBlibzfs_core_init\fR() function shall fail if \fBopen\fR(2) of /dev/zfs +fails. In this situation, the error code from \fBopen\fR(2) will be returned. + +.SH "SEE ALSO" +.sp +.LP +"\fIlibzfs_core.h\fR(3)", "\fIopen\fR(2)" diff --git a/man/man3/lzc_bookmark.3 b/man/man3/lzc_bookmark.3 new file mode 100644 index 000000000000..60e5f52eb681 --- /dev/null +++ b/man/man3/lzc_bookmark.3 @@ -0,0 +1,159 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_bookmark 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_bookmark\fR(\fBnvlist_t *\fR\fIbookmarks\fR, \fBnvlist_t +**\fR\fIerrlist\fR); + +.SH NAME +lzc_bookmark \- Creates bookmarks from snapshot + +.SH DESCRIPTION +.LP +The \fBlibzfs_snapshot\fR() function creates atomic snapshots of all ZFS +datasets and/or volumes named in the \fIsnaps\fR nvlist. + +.I bookmarks +shall be a nvlist containing strings whose keys are bookmark names and values +are snapshot names to specify which bookmarks to create. All bookmarks and +snapshots must be inside the same pool. + +.I errlist +shall contain a handle that shall be used to store a pointer to a library +allocated nvlist when non-NULL and the operation for at least one hold fails. +The names of the holds shall be the keys while the values shall contain the +error codes and be of type int32. Holds that failed to release because they did +not exist shall also have an entry added. It shall not be touched otherwise. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. +.sp +On error, an error is returned from one of the holds where an error occurred +and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific +information when \fIerrlist\fR is non-NULL. The caller must call +\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. + +.SH ERRORS +.sp +.LP +The \fBlzc_bookmark()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +A bookmark with a name specified in \fIbookmarks\fR already exists. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +Multiple bookmarks were specified in \fIbookmarks\fR with the same name. +.sp +The snapshot for a bookmark is not a syntactically valid snapshot. +.sp +\fIbookmarks\fR is not a valid nvlist. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +A bookmark name in the \fIbookmarks\fR nvlist exceeds 256 characters. +.sp +A snapshot name in the \fIbookmarks\fR nvlist exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +A snapshot specified in \fIbookmarks\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIbookmarks\fR to the +kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +The bookmark feature flag is not enabled on this pool. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +\fB\fBEXDEV\fR\fR +.ad +.RS 13n +Multiple pools specified. +.sp +Multiple snapshots per filesystem specified. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_clone.3 b/man/man3/lzc_clone.3 new file mode 100644 index 000000000000..3347ce09bb2d --- /dev/null +++ b/man/man3/lzc_clone.3 @@ -0,0 +1,154 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_clone 3 "2015 JUL 3" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_clone\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR \fIorigin\fR, \fBnvlist_t *\fR\fIprops\fR); + +.SH NAME +lzc_clone \- Creates a clone from a snapshot + +.SH DESCRIPTION +.LP +The +\fBlibzfs_clone\fR() +function creates a ZFS dataset or volume named +.I fsname +from the snapshot +.fs origin . +Properties may optionally be set using +.I props . + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. +.SH ERRORS +.sp +.LP +The \fBlzc_clone()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEDQUOT\fR\fR +.ad +.RS 13n +Creation of the clone will require storage space in excess of the filesystem +quota. +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +A dataset named \fIfsname\fR already exists. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR is not syntactically correct. This includes situations where bookmarks, snapshots or holds are specified. +.sp +The snapshot name \fIorigin\fR is not syntactically correct. This includes the case of attempting to clone a non-snapshot. +.sp +The nvlist_t \fIprops\fR could not be understood by the kernel as being NULL or a nvlist. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR exceeds 256 characters. +.sp +The snapshot name \fIorigin\fR nvlist exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +The dataset \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIprops\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBEOVERFLOW\fR\fR +.ad +.RS 13n +Specified volume size through \fIprops\fR exceeds system supported device size. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBEXDEV\fR\fR +.ad +.RS 13n +Attempted to clone across pools. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_create.3 b/man/man3/lzc_create.3 new file mode 100644 index 000000000000..72c44a1f7432 --- /dev/null +++ b/man/man3/lzc_create.3 @@ -0,0 +1,141 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_create 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_create\fR(\fBconst char *\fR\fIfsname\fR, \fBdmu_objset_type_t\fR \fItype\fR, \fBnvlist_t *\fR\fIprops\fR); + +.SH NAME +lzc_create \- Create a ZFS dataset or volume + +.SH DESCRIPTION +.LP +The +\fBlibzfs_create\fR() +function creates a dataset or zvol according to \fItype\fR. Optional properties +are passed through \fIprops\fR. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. + +.SH ERRORS +.sp +.LP +The \fBlzc_inherit()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR is invalid. +.sp +The dataset type \fItype\fR is invalid. +.sp +The nvlist \fIprops\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The dataset \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIprops\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +The requested ZPL version is not supported. +.sp +A feature has been requested (e.g. normalization) that hte requested ZPL version doe sont support. +.RE + +.sp +.ne 2 +.na +\fB\fBEOVERFLOW\fR\fR +.ad +.RS 13n +Specified volume size exceeds system supported device size. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_destroy_bookmarks.3 b/man/man3/lzc_destroy_bookmarks.3 new file mode 100644 index 000000000000..65a54c24093b --- /dev/null +++ b/man/man3/lzc_destroy_bookmarks.3 @@ -0,0 +1,133 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_destroy_bookmarks 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_destroy_bookmarks\fR(\fBnvlist_t *\fR\fIbmarks\fR, \fBnvlist_t **\fR\fIerrlist\fR); + +.SH NAME +lzc_destroy_bookmarks \- Destroys bookmarks + +.SH DESCRIPTION +.LP +The \fBlzc_destroy_bookmarks\fR() function shall atomically destroy bookmarks +specified within a pool. The pool is determined implicitly from the list of +bookmarks. If \fIerrlist\fR is specified and destruction of a bookmark fails +(e.g. specified name too long), it will be allocated and updated to contain a +list of bookmarks where the operation failed. The keys of the list will be the +full bookmark names while the values will be int32 error codes. +.sp +Bookmarks that do not exist will be silently ignored. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. +.sp +On error, an error is returned from one of the bookmarks where an error +occurred and \fIerrlist\fR is populated with more specific information if a +pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names +and int32 values of the error codes. The caller must call \fBnvlist_free\fR() +on \fIerrlist\fR if this occurs. +.SH ERRORS +.sp +.LP +The \fBlzc_destroy_bookmarks()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +Invalid boomark name specified in \fIbmarks\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +Bookmark name specified in \fIbmarks\fR is too long. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIbmarks\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBEXDEV\fR\fR +.ad +.RS 13n +Bookmarks from different pools were specified. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_destroy_one.3 b/man/man3/lzc_destroy_one.3 new file mode 100644 index 000000000000..d55cec41992b --- /dev/null +++ b/man/man3/lzc_destroy_one.3 @@ -0,0 +1,149 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_destroy_one 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_destroy_one\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIopts\fR); + +.SH NAME +lzc_destroy_one \- Destroys a dataset or volume + +.SH DESCRIPTION +.LP +The \fBlzc_destroy_one\fR() function shall destroys a dataset or a volume. +Destroying snapshots and bookmarks is not currently supported. Call +lzc_destroy_snaps and lzc_destroy_bookmarks for those respectively. + +The only currently valid property is the boolean "defer". It makes destruction +asynchronous such that the only error code back is if we try to destroy +something that does not exist. The caller must unmount the dataset before +calling this. Otherwise, it will fail. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. +.sp +On error, an error is returned from one of the bookmarks where an error +occurred and \fIerrlist\fR is populated with more specific information if a +pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names +and int32 values of the error codes. The caller must call \fBnvlist_free\fR() +on \fIerrlist\fR if this occurs. +.SH ERRORS +.sp +.LP +The \fBlzc_destroy_one()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEBUSY\fR\fR +.ad +.RS 13n +Dataset named \fIdataset\fR has a long hold from a zfs send stream or a user +hold from \fBlzc_hold\fR(). +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +The dataset or volume \fIfsname\fR has children in its pool's namespace. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The string \fIfsname\fR is an invalid name for a dataset or volume. +.sp +The \fIopts\fR nvlist is neither NULL nor a valid nvlist. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIfsname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The string \fIfsname\fR does not name a dataset that exists. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIbmarks\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +\fIdefer\fR specified, but pool version predates version 18 +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_destroy_snaps.3 b/man/man3/lzc_destroy_snaps.3 new file mode 100644 index 000000000000..99cbffd6053d --- /dev/null +++ b/man/man3/lzc_destroy_snaps.3 @@ -0,0 +1,159 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_destroy_snaps 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_destroy_snaps\fR(\fBnvlist_t *\fR\fIsnaps\fR, \fBboolean_t\fR \fIdefer\fR, \fBnvlist_t **\fR\fIerrlist\fR); + +.SH NAME +lzc_destroy_snaps \- Destroy snapshots + +.SH DESCRIPTION +.LP +The \fBlzc_destroy_snaps\fR() function destroys snapshots specified via strings +through the nvlist \fRsnaps\fR. They must all be in the same pool. +.sp +Snapshots that do not exist will be silently ignored. +.sp +If \fIdefer\fR is not set, and a snapshot has user holds or clones, the +destroy operation will fail and none of the snapshots will be +destroyed. +.sp +If \fIdefer\fR is set, and a snapshot has user holds or clones, it will be +marked for deferred destruction, and will be destroyed when the last hold +or clone is removed/destroyed. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. This means that all snapshots were +destroyed (excluding those that did not exist) or were marked for later +distruction if \fIdefer\fR is set. +.sp +On error, an error is returned from one of the snapshots where an error +occurred and \fIerrlist\fR is populated with more specific information if a +pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names +and int32 values of the error codes. The caller must call \fBnvlist_free\fR() +on \fIerrlist\fR if this occurs. +.SH ERRORS +.sp +.LP +The \fBlzc_destroy_snaps()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEBUSY\fR\fR +.ad +.RS 13n +Snapshot held by a user hold and \fIdefer\fR is not specified. +.sp +Snapshot held by a zfs send stream and \fIdefer\fR is not specified. +.sp +Snapshot held by an open file hanle or program's present working directory and +\fIdefer\fR is not specified. +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +This snapshot is the parent of clones and cannot be deleted. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +No snaphsots specified in \fIsnaps\fR. +.sp +The nvlist \fIsnaps\fR is not a valid nvlist. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +Snapshot name specified in \fIsnaps\fR is too long. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The dataset \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIprops\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +\fIdeferred\fR specified on pool that is earlier than version 18. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_exists.3 b/man/man3/lzc_exists.3 new file mode 100644 index 000000000000..97bd8ed71fe0 --- /dev/null +++ b/man/man3/lzc_exists.3 @@ -0,0 +1,68 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_exists 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBboolean_t\fR \fBlzc_exists\fR(\fBconst char *\fR\fIdataset\fR); + +.SH NAME +lzc_exists \- Test for dataset existence. + +.SH DESCRIPTION +.LP +The +\fBlzc_exists\fR() +function tests whether +.I dataset +exists. It is more efficient than calling +\fBlzc_list\fR(), +but it does not apply to bookmarks. + +.SH RETURN VALUES +.sp +.LP +On success, the +\fBlzc_exists\fR() +function returns a 0 (B_TRUE) when +.I dataset +exists and 1 (B_FALSE) when +.I dataset +does not exist. On failure, the function returns an error code. + +.SH ERRORS +.sp +.LP +The \fBlzc_exists()\fR function should never return an error when the library +has been properly initialized. + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_list\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_get_bookmarks.3 b/man/man3/lzc_get_bookmarks.3 new file mode 100644 index 000000000000..b15b0485423c --- /dev/null +++ b/man/man3/lzc_get_bookmarks.3 @@ -0,0 +1,165 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_get_boomarks 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. The location of +the header might vary on different systems. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_get_bookmarks\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIprops\fR, \fBnvlist_t **\fR\fIbmarks\fR); + +.SH NAME +lzc_get_bookmarks \- Retrieve bookmarks of a given filesystem + +.SH DESCRIPTION +.LP +The \fBlzc_get_bookmarks\fR() function will retrieve the list of bookmarks for +the given file system. The \fIprops\fR parameter is an nvlist of property names +(with no values) that will be returned for each bookmark. The \fIbmarks\fR +parameter is a pointer to a nvlist of the bookmarks. The caller is responsible +for freeing it with \fBnvlist_free\fR(). + +The format of the returned nvlist as follows: +.P + -> { + -> { + "value" -> uint64 + } +.br +} + +The following are valid properties on bookmarks. All of them are uint64 values +in the nvlist: +.sp +.na +\fB\fBguid\fR\fR +.ad +.RS +Globally unique identifier of the referenced snapshot +.RE + +.na +\fB\fBcreatetxg\fR\fR +.ad +.RS +Number of transaction group (txg) when the snapshot provided to the bookmark was created +.RE + +.na +\fB\fBcreation\fR\fR +.RS +UNIX timestamp when the snapshot used to make the bookmark was created +.RE + +.sp +Unsupported properties will be silently ignored. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. + +.SH ERRORS +.sp +.LP +The \fBlzc_inherit()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR is invalid. +.sp +The nvlist \fIprops\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The dataset \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIprops\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBESRCH\fR\fR +.ad +.RS 13n +A specified, but valid, bookmark was not found. This merits a bug report. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_get_holds.3 b/man/man3/lzc_get_holds.3 new file mode 100644 index 000000000000..80f72ddd37b9 --- /dev/null +++ b/man/man3/lzc_get_holds.3 @@ -0,0 +1,129 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_get_holds 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_get_holds\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t **\fR\fIholdsp\fR); + +.SH NAME +lzc_get_holds \- Retrieve list of user holds on the specified snapshot. + +.SH DESCRIPTION +.LP +The \fBlzc_get_holds\fR() function returns a nvlist of holds on the snapshot. +The nvlist keys will be the short names of the holds while the nvlist values +will be uint64 numbers. The numbers are internal identifiers that have no +application to userland in the current iteration of the libzfs_core API. + +.SH RETURN VALUE +On success, the \fBlzc_get_holds\fR() function returns 0 and fills in +\fI*holdsp\fR when \fIholdsp\R is non-NULL. On failure, the function returns an +error code. + +.SH ERRORS +.BR lzc_get_holds () +can fail with the following errors: + +.TP +.B ENOENT +Pool does not exist, or if unintialized, the cachefile is out of +sync because loading the pool failed due to an exported or +destroyed pool. If pool exists, snapshot does not exist. +.TP +.B EEXIST +The pool was uninitialized and a pool with the same GUID already +existed. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. + +.SH ERRORS +.sp +.LP +The \fBlzc_inherit()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The snapshot name \fIsnapname\fR is not syntactically correct. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or +destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was +read from the cachefile. +.sp +The snapshot \fIsnapname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), \fBlzc_release\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_hold.3 b/man/man3/lzc_hold.3 new file mode 100644 index 000000000000..388772e26e3b --- /dev/null +++ b/man/man3/lzc_hold.3 @@ -0,0 +1,182 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_hold 7 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_hold\fR(\fBnvlist_t *\fR\fIholds\fR, \fBint\fR \fIcleanup_fd\fR, \fBnvlist_t **\fR\fIerrlist\fR); +.sp +\fBint\fR \fBlzc_release\fR(\fBnvlist_t *\fR\fIholds\fR, \fBnvlist_t **\fR\fIerrlist\fR); + + +.SH NAME +lzc_hold, lzc_release \- Creates and releases user holds on snapshots + +.SH DESCRIPTION +.LP +The \fBlzc_hold\fR() function creates user holds on snapshots. If there is a +hold on a snapshot, the snapshot can not be destroyed. +.sp +However, it can be marked for deletion by calling \fBlzc_destroy_snaps\fR() +with defer=B_TRUE. Snapshots preserved in the way shall be destroyed as the +user hold is removed. +.sp +\fBlzc_release\fR() shall explicitly release a hold. If the snapshot has been +marked for deferred destroy by calling \fBlzc_destroy_snaps\fR() with +defer=B_TRUE, it does not have any clones, and all the user holds are removed, +then the snapshot shall be destroyed. + +.I snaps +shall be a nvlist with zfs snapshots to hold to hold. It shall store string +keys that are the snapshots and values that are the hold names. + +.I cleanup_fd +shall be a file descriptor that specifies thta the hold is temporary and is to +be closed when the specified file descriptor is closed. Specifying the file +descriptor 0 disables this behavior while specifying the file descriptor -1 +shall make the hold close when the file descriptor for /dev/zfs held by the +library is closed. + +.I errlist +shall contain a handle that shall be used to store a pointer to a library +allocated nvlist when non-NULL and the operation for at least one hold fails. +The names of the holds shall be the keys while the values shall contain the +error codes and be of type int32. Holds that failed to release because they +did not exist shall also have an entry added. It shall not be touched +otherwise. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. +.sp +On error, an error is returned from one of the holds where an error occurred +and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific +information when \fIerrlist\fR is non-NULL. The caller must call +\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. + +.SH ERRORS +.sp +.LP +The \fBlzc_hold()\fR function shall fail if: +.sp +.ne 2 +.na +\fB\fBE2BIG\fR\fR +.ad +.RS 13n +The hold short name exceeds 256 or 238 in the case of a temporary +hold. +.RE + +.sp +.ne 2 +.na +\fB\fBEBADF\fR\fR +.ad +.RS 13n +The file descriptor \fIcleanup_fd\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +A hold with a name specified in \fIsnaps\fR already exists. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The nvlist \fIsnaps\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +A snapshot or hold name specified in \fIsnaps\fR nvlist exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +A snapshot specified in \fIsnaps\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIsnaps\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +Called on a pool that is earlier than version 18. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_get_holds\fR(3), \fBlzc_destroy_holds\fR(3), +\fBzfs\fR(8) diff --git a/man/man3/lzc_inherit.3 b/man/man3/lzc_inherit.3 new file mode 100644 index 000000000000..96d9c9d0def1 --- /dev/null +++ b/man/man3/lzc_inherit.3 @@ -0,0 +1,145 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_inherit 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_inherit\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR\fIpropname\fR, \fBnvlist_t *\fR\fIopts\fR); + +.SH NAME +lzc_inherit \- Reset dataset property to default value + +.SH DESCRIPTION +.LP +The +\fBlzc_inherit\fR() +function shall atomically reset property \fIpropname\fR of dataset +\fIfsname\fR. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. +.SH ERRORS +.sp +.LP +The \fBlzc_inherit()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR is invalid. +.sp +The property name \fIpropname\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIpropname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIopts\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The dataset \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOSPC\fR\fR +.ad +.RS 13n +Not enough space to update property. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +Called \fBlzc_inherit()\fR for \fIpropname\fR property on a pool those version predates its introduction. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBEROFS\fR\fR +.ad +.RS 13n +Attempted to inherit volsize on readonly zvol. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_list.3 b/man/man3/lzc_list.3 new file mode 100644 index 000000000000..8fbc02d181d1 --- /dev/null +++ b/man/man3/lzc_list.3 @@ -0,0 +1,374 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_list 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_list\fR(\fBconst char *\fR\fIname\fR, \fBnvlist_t +*\fR\fIopts\fR) + +.SH NAME +lzc_list \- List filesystems, volumes, snapshots and bookmarks + +.SH DESCRIPTION +.LP +The \fBlzc_list\fR() function writes a series of records to the output method +specified in the nvlist \fIopts\fR. It is designed to provide a large subset of +the functionality of the \fBzfs list\fR subcommand and operates similarly to +it. At present, the only supported output method is an asynchronous file +descriptor. + +.I name +The name of the pool, dataset, snapshot or volume to list by writing to fd. If +NULL, a description of all pools is written to fd. + +.I opts +A nvlist used to manipulate output. It takes these values: +.sp +.in +2 +.nf +NAME TYPE DESCRIPTION +"fd" int32 UNIX file descriptor for output. +"recurse" boolean/uint64 List output for children. +"type" nvlist List only types specified. +.fi +.in -2 +.sp +At present, the fd field is the only supported output method and therefore, it +is mandatory. If the name field is a bookmark or snapshot, the recurse field +is ignored. If the passed name is that of a bookmark or snapshot, the recurse +field is ignored. If all children are desired, recurse should be set to be a +boolean type. If a recursion limit is desired, recurses hould be a uint64_t. If +no type is specified, a default behavior consistent with the zfs list command +is provided. Valid children of the type nvlist are: +.sp +.in +2 +.nf +NAME TYPE DESCRIPTION +"all" boolean List output for all types +"bookmark" boolean List output for bookmarks +"filesystem" boolean List output for filesystems +"snap" boolean List output for snapshots +"snapshot" boolean List output for snapshots +"volume" boolean List output for volumes +.fi +.in -2 +.sp +Whenever a boolean type is specified, any type may be passed and be +considered boolean. However, future extensions may accept alternate types +and consequently, backward compatibility is only guarenteed to callers +passing a boolean type that contains no value. A boolean that contains +B_TRUE or B_FALSE is considered a separate type from a boolean that contains +no value. Additionally, future enhancements to zfs may create a new type and +callers that only wish to handle existing types should specify them +explicitly rather than relying on the default behavior. +.sp +The parent-child relationship is obeyed such all children of each +pool/directory are output alongside their parents. However, no guarantees +are made with regard to post-order/pre-order traversal or the order of +bookmarks/snapshots, such that the order is allowed to change. Userland +applications that are sensitive to a particular output order are expected to +sort. +.sp +The output consists of a record header followed immediately by XDR-encoded +nvlist. The header format is as follows: +.sp +.in +2 +.nf +OFFSET SIZE DESCRIPTION +0 bytes 4 bytes XDR-nvlist size (unsigned) +4 bytes 1 byte Header extension space (unsigned) +5 bytes 1 byte Return code (unsigned) +6 bytes 1 byte Endian bit (0 is BE, 1 is LE) +7 bytes 1 byte Reserved +.fi +.in -2 +.sp +Errors obtaining information for any record will be contained in the return +code. The output for any record whose header return code contains an error +is a XDR encoded nvlist whose contents are undefined, unless the size +provided in the header is zero, in which case the output for that record is +empty. The receiver is expected to check the endian bit field before +processing the XDR-nvlist size and perform a byte-swap operation on the +value should the endian-ness differ. +.sp +Non-zero values in the reserved field and upper bits of the endian field +imply a back-incompatible change. If the header extension field is non-zero +when neither the reserved field nor the upper bits of the endian field are +non-zero, the header should be assumed to have been extended in a +backward-compatible way and the XDR-nvlist of the specified size shall +follow the extended header. The lzc_list() library call will always request +API version 0 request as part of the ioctl to userland. Consequently, the +kernel will return an API version 0 compatible-stream unless a change is +requested via a future extension to the opts nvlist. +.sp +The nvlist will have the following members: +.sp +.in +2 +.nf +NAME TYPE DESCRIPTION +"name" string SPA/DSL name +"dmu_objset_stats" nvlist DMU Objset Stats +"properties" nvlist DSL properties +.fi +.in -2 +.sp +Additional members may be added in future extensions. +.sp +The "dmu_objset_stats" will have the following members: +.sp +.in +2 +.nf +NAME TYPE DESCRIPTION +"dds_num_clones" uint64_t Number of clones +"dds_creation_txg" uint64_t Creation transaction group +"dds_guid" uint64_t Globally unique identifier +"dds_type" string Type +"dds_is_snapshot" boolean Is a snapshot +"dds_inconsistent" boolean Is being received or destroyed +"dds_origin" string Name of parent +.fi +.in -2 +.sp +Additional members may be added in future extensions. +.sp +The "dds_" prefix stands for "DSL Dataset". "dds_type" is a string +representation of internal object types. Valid values at this time are: +.sp +.in +2 +.nf +NAME PUBLIC DESCRIPTION +"NONE" No Uninitialized value +"META" No Metadata +"ZPL" Yes Dataset +"ZVOL" Yes Volume +"OTHER" No Undefined +"ANY" No Open +.fi +.in -2 +.sp +Only the public values will be returned for any output. The return of a +value not on this list implies a record for a new storage type. The output +should be consistent with existing types and the receiver can elect to +either handle it in a manner consistent with existing types or skip it. +Under no circumstance will an unlisted type be returned when types were +explicitly provided via the opts nvlist. +.sp +On bookmarks, the "dmu_objset_stats" of the parent DSL Dataset shall be +returned. Consequently, "dds_is_snapshot" shall be false and identification +of bookmarks shall be done by checking for the '#' character in the "name" +member of the top level nvlist. This is done so that the type of the +bookmarked DSL dataset may be known. +.sp +End of output shall be signified by NULL record header. Userland is expected +to close the file descriptor. Early termination can be signaled from +userland by closing the file descriptor. +.sp +The design of the output is intended to enable userland to perform readahead +on the file descriptor. On certain platforms, libc may provide output +buffering. Userland libraries and applications electing to perform readahead +should take care not to block on a partially filled buffer when an end of +stream NULL record is returned. +.sp +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. +.sp +On error, an error is returned from one of the holds where an error occurred +and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific +information when \fIerrlist\fR is non-NULL. The caller must call +\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. + +.SH ERRORS +.sp +.LP +The \fBlzc_list()\fR function shall fail if: +.sp +.ne 2 +.na +\fB\fBEAGAIN\fR\fR, \fB\fBEWOULDBLOCK\fR\fR +.ad +.RS 13n +The file descriptor was marked non-blocking and the call would block. This is +from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEBADE\fR\fR +.ad +.RS 13n +An uncorrectable checksum failure was encountered. +.RE + +.sp +.ne 2 +.na +\fB\fBEBADF\fR\fR +.ad +.RS 13n +The file descriptor "\fIfd\fR" in the \fIopts\fR nvlist is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBEDESTADDRREQ\fR\fR +.ad +.RS 13n +The file descriptor is a datagram socket for which a peer address has not been +set using \fBconnect\fR(2). This is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEFAULT\fR\fR +.ad +.RS 13n +Internal issue occurred when copying command data from userland to kernel. See +Illumos ddi_copyin(9F). +.RE + +.sp +.ne 2 +.na +\fB\fBEFBIG\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR in the \fIopts\fR nvlist is a file and writing to +it would cause it to exceed the maximum file size permitted by the filesystem. +This is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEIO\fR\fR +.ad +.RS 13n +A low level error occurred. This is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The string \fIname\fR is not a valid pool, dataset, volume, snapshot or bookmark name. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +Nothing named \fIname\fR exists. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIopts\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOSPC\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR in the \fIopts\fR nvlist cannot be appended. This +is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEPIPE\fR\fR +.ad +.RS 13n +The file descriptor is a pipe whose reading end is closed. This is from +\fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH ERRATA +Unlike other \fBlzc_*\fR() functions, the output of this function is non-atomic. +Consequently, rename, creation, destruction and property creation operations +can race with it. Avoiding this requires allowing userland to block the kernel +when it holds key locks required for the aforementioned operations, which is a +denial of service vulnerability. Userland consumers must handle edge cases +where concurrent operations cause the output to be inconsistent. One example is +that renames can cause datasets to appear twice (or not at all) depending on +what has been output and where the rename moves a dataset, volume, snapshot or +bookmark. + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_promote.3 b/man/man3/lzc_promote.3 new file mode 100644 index 000000000000..5a6d7a0c309d --- /dev/null +++ b/man/man3/lzc_promote.3 @@ -0,0 +1,139 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_promote 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_promote\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIopts\fR); + +.SH NAME +lzc_promote \- Reverse clone parent-child relationship + +.SH DESCRIPTION +.LP +The \fBlzc_promote\fR() function promotes a clone file system \fIfsname\fR to +no longer be dependent on its "origin" snapshot. This makes it possible to +destroy the file system from which the clone was created. The clone +parent-child dependency relationship is reversed, so that the origin file +system becomes a clone of the specified file system. + +The snapshot that was cloned, and any snapshots previous to this snapshot, are +now owned by the promoted clone. The space they use moves from the origin file +system to the promoted clone, so enough space must be available to accom‐ +modate these snapshots. No new space is consumed by this operation, but the +space accounting is adjusted. The promoted clone must not have any conflicting +snapshot names of its own. The rename subcommand can be used to rename any +conflicting snapshots. + +The nvlist \fIopts\fR is reserved for future extensions that provide options +that alter the behavior of the lzc_promote() function. At the time of writing, +all data passed to it is ignored and callers should pass NULL to ensure that +behavior remains the same with future extensions. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. +.SH ERRORS +.sp +.LP +The \fBlzc_promote()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIfsname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIopts\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The clone \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOSPC\fR\fR +.ad +.RS 13n +Not enough space to update property. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_receive.3 b/man/man3/lzc_receive.3 new file mode 100644 index 000000000000..14c603660759 --- /dev/null +++ b/man/man3/lzc_receive.3 @@ -0,0 +1,237 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_receive 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_receive\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t +*\fR\fIprops\fR, \fBconst char *\fR\fIorigin\fR, \fBboolean_t\fR \fIforce\fR, +\fBint\fR \fIfd\fR); + +.SH NAME +lzc_receive \- Create a snapshot from a zfs send stream + +.SH DESCRIPTION +.LP +The \fBlzc_receive\fR() function reads a zfs send stream from the file +descriptor \fIfd\fR to atomically create the snapshot \fIsnapname\fR. Any +properties specified by \fIprops\fR shall be set as received properties. + +If the stream is a clone, its origin snapshot must be specified by \fIorigin\fR. +The \fIforce\fR flag will cause the target filesystem to be rolled back or +destroyed if necessary to receive the send stream. + +This interface does not work on deduplicated streams (those with +DMU_BACKUP_FEATURE_DEDUP) at this time. Also, O_NONBLOCK is not supported on +\fIfd\fR. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. +.sp +On error, an error is returned from one of the holds where an error occurred +and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific +information when \fIerrlist\fR is non-NULL. The caller must call +\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. + +.SH ERRORS +.sp +.LP +The \fBlzc_receive()\fR function shall fail if: +.sp +.ne 2 +.na +\fB\fBEAGAIN\fR\fR, \fB\fBEWOULDBLOCK\fR\fR +.ad +.RS 13n +The file descriptor was marked non-blocking and the call would block. This is +from \fBread\fR(2). This indicates a userland programming bug because \fIfd\fB +should never be set as being non-blocking. +.RE + +.sp +.ne 2 +.na +\fB\fBEBADE\fR\fR +.ad +.RS 13n +Checksum failure in stream. +.RE + +.sp +.ne 2 +.na +\fB\fBEBADF\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBEBUSY\fR\fR +.ad +.RS 13n +The \fIorigin\fR has a long hold (i.e. it is mounted). +.RE + + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEFAULT\fR\fR +.ad +.RS 13n +Internal issue occurred when copying command data from userland to kernel. See +Illumos ddi_copyin(9F). +.RE + +.sp +.ne 2 +.na +\fB\fBEIO\fR\fR +.ad +.RS 13n +Reading the dmu replay record header from the file descriptor failed. +.sp +A low level error occurred. This is from \fBread\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEINTR\fR\fR +.ad +.RS 13n +The call was interrupted by a userspace signal. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR is not a valid bookmark or snapshot name. +.sp +The \fIorigin\fR is specified, but \fIorigin\fR and \fIsnapname\fR are not both snapshots. +.sp + +.RE + +.sp +.ne 2 +.na +\fB\fBEISDIR\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR belongs to a directory. This is from \fBread\fR(2). +.RE + +:sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The snapshot or bookmark named \fIsnapname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIparams\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOSPC\fR\fR +.ad +.RS 13n +The pool is out of space. +.sp +The inherited quotas and reservations do not allow for more space to be used. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBETXTBSY\fR\fR +.ad +.RS 13n +The force flag has not been set, but the dataset belonging to \fRsnapname\fI has been modified. +.RE + + +.SH BUGS +File descriptors with O_NONBLOCK do not fail immediately. + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), \fBlzc_receive\fR(3), \fBwrite\fR(2), +\fBzfs\fR(8) diff --git a/man/man3/lzc_release.3 b/man/man3/lzc_release.3 new file mode 100644 index 000000000000..c9c61c3fa6c9 --- /dev/null +++ b/man/man3/lzc_release.3 @@ -0,0 +1 @@ +.so man3/lzc_hold.3 diff --git a/man/man3/lzc_rename.3 b/man/man3/lzc_rename.3 new file mode 100644 index 000000000000..6fa2c3f6e32f --- /dev/null +++ b/man/man3/lzc_rename.3 @@ -0,0 +1,132 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_rename 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_rename\fR(\fBconst char *\fR\fIoldname\fR, \fBchar *\fR\fInewname\fR, \fBnvlist_t *\fR\fIopts\fR, \fBchar **\fR\fIerrname\fR); + +.SH NAME +lzc_rename \- Rollback this filesystem or volume to its most recent snapshot. + +.SH DESCRIPTION +.LP +The \fBlibzfs_rename\fR() function will rename a dataset, volume or snapshot. + +For legacy purposes, it will make an attempt to unmount the dataset, volume or +snapsot before a rename is done. To ensure atomicity, userland should unmount +the dataset, volume or snapshot before calling this. + +.I oldname +shall be the name of the current dataset. + +.I newname +shall be the new name of the dataset. + +.I opts +shall be an nvlist_t that allows changes to the behavior. The only option +accepted at this time is the boolean "recursive" key. That will rename +snapshots of child datasets. This is intended to complement +\fBlzc_snapshot\fR() when multiple snapshots are made with the same name. + +.I errname +shall be a pointer to a string pointer. It can be NULL. It is only used when an +error occurs when renaming snapshots recursively. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. + +If an error occurs on a recursive snapshot rename and \fIerrname\fR is +non-NULL, a strdup()-allocated string wll be returned via \fIerrname\fR. The +caller must free it with \fBstrfree\fR(). + +.SH ERRORS +.sp +.LP +The \fBlzc_rename()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEBUSY\fR\fR +.ad +.RS 13n +The dataset has a hold. +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIfsname\fR exceeds 256 characters. +.sp +The string \fInewname\fR exceeds 256 characters. +.sp +The new name of a recursively renamed child snapshot would exceed 256 +characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_snapshot\fR(3), \fBstrdup\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_rollback.3 b/man/man3/lzc_rollback.3 new file mode 100644 index 000000000000..cc5e3f744ce6 --- /dev/null +++ b/man/man3/lzc_rollback.3 @@ -0,0 +1,143 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_rollback 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_rollback\fR(\fBconst char *\fR\fIfsname\fR, \fBchar *\fR\fIsnapnamebuf\fR, \fBint\fR \fIsnapnamelen\fR); + +.SH NAME +lzc_rollback \- Rollback this filesystem or volume to its most recent snapshot. + +.SH DESCRIPTION +.LP +The \fBlzc_rollback\fR() function rolls back a live dataset or volume to its most recent snapshot. + +.I fsname +shall be the name of the most recent snapshot to rollback. + +.I snapnamebuf +shall be a pointer to a string to fill with the name of the most recent +snapshot. If NULL, it wll be ignored. + +.I snapnamelen +shall be the length of \fIsnapnamebuf\fR. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned and \fIsnapnamebuf\fR is filled if +non-NULL. Otherwise, an error is returned. + +.SH ERRORS +.sp +.LP +The \fBlzc_rollback()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEBUSY\fR\fR +.ad +.RS 13n +The dataset has a hold. +.RE + +.sp +.ne 2 +.na +\fB\fBEDQUOT\fR\fR +.ad +.RS 13n +The snapshot uses more data than th file system quota. +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +\fIfsname\fR must be the most recent snapshot. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIfsname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +A dataset or volume specified in \fIsnaps\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOSPC\fR\fR +.ad +.RS 13n +Not enough space to rollback snapshot. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE +. +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_snapshot\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_send.3 b/man/man3/lzc_send.3 new file mode 100644 index 000000000000..0e8cc02bdd67 --- /dev/null +++ b/man/man3/lzc_send.3 @@ -0,0 +1,220 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_send 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_send\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char +*\fR\fIfrom\fR, \fBint\fR \fIfd\fR, \fBenum lzc_send_flags\fR \fIflags); + +.SH NAME +lzc_send \- Generate a send stream from a snapshot + +.SH DESCRIPTION +.LP +The \fBlzc_send\fR() function writes a ZFS stream to +file descriptor \fIfd\fR from snapshot \fIsnapname\fR of dataset \fIfrom\fR. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. +.sp +On error, an error is returned from one of the holds where an error occurred +and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific +information when \fIerrlist\fR is non-NULL. The caller must call +\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. + +.SH ERRORS +.sp +.LP +The \fBlzc_send()\fR function shall fail if: +.sp +.ne 2 +.na +\fB\fBEAGAIN\fR\fR, \fB\fBEWOULDBLOCK\fR\fR +.ad +.RS 13n +The file descriptor was marked non-blocking and the call would block. This is +from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEBADF\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBEDESTADDRREQ\fR\fR +.ad +.RS 13n +The file descriptor is a datagram socket for which a peer address has not been +set using \fBconnect\fR(2). This is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEFAULT\fR\fR +.ad +.RS 13n +Internal issue occurred when copying command data from userland to kernel. See +Illumos ddi_copyin(9F). +.RE + +.sp +.ne 2 +.na +\fB\fBEFBIG\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR is a file and writing to it would cause it to +exceed the maximum file size permitted by the filesystem. This is from +\fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEIO\fR\fR +.ad +.RS 13n +A low level error occurred. This is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEINTR\fR\fR +.ad +.RS 13n +The call was interrupted by a userspace signal. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR is not a valid bookmark or snapshot name. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The snapshot or bookmark named \fIsnapname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIparams\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOSPC\fR\fR +.ad +.RS 13n +The file descriptor \fIfd\fR cannot be appended. This is from \fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEPIPE\fR\fR +.ad +.RS 13n +The file descriptor is a pipe whose reading end is closed. This is from +\fBwrite\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBESRCH\fR\fR +.ad +.RS 13n +A specified, but valid, bookmark was not found. This merits a bug report. +.RE + +.SH BUGS +File descriptors with O_NONBLOCK do not fail immediately. + +.SH SEE ALSO +.sp +.LP +\fBconnect\fR(2) \fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), +\fBlzc_receive\fR(3), \fBwrite\fR(2), \fBzfs\fR(8) diff --git a/man/man3/lzc_send_progress.3 b/man/man3/lzc_send_progress.3 new file mode 100644 index 000000000000..c59149fd75d7 --- /dev/null +++ b/man/man3/lzc_send_progress.3 @@ -0,0 +1,111 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_send_progress 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_send_progress\fR(\fBconst char *\fR\fIsnapname\fR, \fBint\fR \fIfd\fR, \fBuint64_t *\fR\fIbytesp\fR); + +.SH NAME +lzc_send_progress \- Query bytes written to fd by active send stream + +.SH DESCRIPTION +.LP +The +\fBlzc_send_progress\fR() +function returns how many bytes have been written by send stream to \fIfd\fR. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned and \fI*bytesp\fR is updated. +Otherwise, an error is returned. +.SH ERRORS +.sp +.LP +The \fBlzc_send_progress()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The snapshot name \fIsnapname\fR is not syntactically correct. +.RE +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR exceeds 256 characters. +.RE + + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loadng unitialized pool from cachefile failed because the pool was exported or +destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was +read from the cachefile. +.sp +The snapshot \fIsnapname\fR does not exist. +.sp +No active send stream was found that maches \fIfd\fR and \fIsnapname\fR +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_send\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_send_space.3 b/man/man3/lzc_send_space.3 new file mode 100644 index 000000000000..e06700e97c4d --- /dev/null +++ b/man/man3/lzc_send_space.3 @@ -0,0 +1,127 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_send_space 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_send_space\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char *\fR\fIfrom\fR, \fBuint64_t *\fR\fIspacep\fR); + +.SH NAME +lzc_send_space \- Calculates approximately how many bytes would be written by +lzc_send(). + +.SH DESCRIPTION +.LP +The \fBlzc_send_space\fR() function calculates approximately how many bytes +would be written by lzc_send(). + +If \fIfrom\fR is NULL, the space for a non-incremental stream is calculated. +Calculations for deduplicated streams are not supported. +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned and \fI*spacep\fR is updated. +Otherwise, an error is returned. +.SH ERRORS +.sp +.LP +The \fBlzc_send_space()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The snapshot name \fIsnapname\fR is not syntactically correct. +.sp +The snapshot name \fIfrom\fR is not syntactically correct. +.RE +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIsnapname\fR exceeds 256 characters. +.sp +The string \fIfrom\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loadng unitialized pool from cachefile failed because the pool was exported or +destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was +read from the cachefile. +.sp +The snapshot \fIsnapname\fR does not exist. +.sp +The snapshot \fIfrom\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBEXDEV\fR\fR +.ad +.RS 13n +The snapshot \fIfrom\fR is not an earlier snapshot than the snapshot \fIsnapname\fR. +.sp +The snapshot \fIfrom\fR and the snapshot \fIsnapname\fR are not snapshots of the same dataset. Alternatively, they are not of the same pool. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBlzc_send\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_set_props.3 b/man/man3/lzc_set_props.3 new file mode 100644 index 000000000000..9a0f4136c151 --- /dev/null +++ b/man/man3/lzc_set_props.3 @@ -0,0 +1,212 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_set_props 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_set_props\fR(\fBconst char *\fR\fIfsname\fR, \fBnvlist_t *\fR\fIprops\fR, \fBboolean_t\fR \fIreceived\fR); + +.SH NAME +lzc_set_props \- Set properties on a filesystem or volume + +.SH DESCRIPTION +.LP +The \fBlzc_set_props\fR() function will set properties on a given dataset or volume. +.sp +.I fsname +is a string containing the name of a dataset or filesystem. +.sp +.I props +is a nvlist containing the properties to set. See \fBzfs\fR(8) for descriptions +of properties. +.sp +.I opts +is a nvlist containing additional options to pass to this command. +.sp +The \fIprops\fR parameter is an nvlist of property names +(with no values) that will be returned for each bookmark. The \fIbmarks\fR +parameter is a pointer to a nvlist of the bookmarks. The caller is responsible +for freeing it with \fBnvlist_free\fR(). + +The format of the returned nvlist as follows: +.P + -> { + -> { + "value" -> uint64 + } +.br +} + +The following are valid properties on bookmarks. All of them are uint64 values +in the nvlist: +.sp +.na +\fB\fBguid\fR\fR +.ad +.RS +Globally unique identifier of the referenced snapshot +.RE + +.na +\fB\fBcreatetxg\fR\fR +.ad +.RS +Number of transaction group (txg) when the snapshot provided to the bookmark was created +.RE + +.na +\fB\fBcreation\fR\fR +.RS +UNIX timestamp when the snapshot used to make the bookmark was created +.RE +.sp + Currently, the \fIopts\fR argument has two additional options. +.sp +.I received +A boolean property that specifies that the properties being set were received from a send stream. +.sp +.I noatomic +tells the kernel to handle failures by setting all properties that do not fail. +This is necessary when setting old-style special properties. +.sp +There are 9 old-style special properties that cannot be set atomically with the others. They are: +.sp +filesystem_limit +.sp +groupquota@ +.sp +groupused@ +.sp +snapdev +.sp +snapshot_limit +.sp +userquota@ +.sp +userused@ +.sp +version +.sp +volsize +.sp +Unsupported properties will be silently ignored. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned and all properties have been set. Otherwise, an error is returned. + +.SH ERRORS +.sp +.LP +The \fBlzc_inherit()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR is invalid. +.sp +The nvlist \fIprops\fR is invalid. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The dataset name \fIfsname\fR exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +The dataset \fIfsname\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIprops\fR to the kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +An old-style special property was specified without "noatomic" in \fBopts\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBESRCH\fR\fR +.ad +.RS 13n +A specified, but valid, bookmark was not found. This merits a bug report. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_snaprange_space.3 b/man/man3/lzc_snaprange_space.3 new file mode 100644 index 000000000000..8e9eb295e247 --- /dev/null +++ b/man/man3/lzc_snaprange_space.3 @@ -0,0 +1,133 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_snaprange_space 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_snaprange_space\fR(\fBconst char *\fR\fIfirstsnap\fR, \fBconst char *\fR\fIlastsnap\fR, \fBuint64_t *\fR\fIusedp\fR); + +.SH NAME +lzc_snaprange_space \- Determine how much space is used by a snapshot range. + +.SH DESCRIPTION +.LP +The +\fBlzc_snaprange_space\fR() +function calculates how much space in bytes the differences between +\fIfirstsnap\fR and \fIlastsnap\fR use in the pool. They must be snapshots of +the same dataset. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. +.SH ERRORS +.sp +.LP +The \fBlzc_snaprange_space()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +A dataset named \fIfsname\fR already exists. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +The snapshot name \fIfirstsnap\fR is not syntactically correct. +.sp +The snapshot name \fIlastsnap\fR is not syntactically correct. +.RE +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +The string \fIfirstsnap\fR exceeds 256 characters. +.sp +The string \fIlastsnap\fR exceeds 256 characters. +.RE + + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loadng unitialized pool from cachefile failed because the pool was exported or +destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was +read from the cachefile. +.sp +The snapshot \fIfirstsnap\fR does not exist. +.sp +The snapshot \fIlastsnap\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +\fB\fBEXDEV\fR\fR +.ad +.RS 13n +\fIfirstsnap\fR must be an earlier snapshot than \fIlastsnap\fR. +.sp +\fIfirstsnap\fR and \fIlastsnap\fR are not from the same dataset. +.RE + +.SH BUGS +.LP +Early implementations of the API will return \fB\fBENOENT\fR\fR instead of +\fB\fBEXDEV\fR\fR. The same implementations would also segfault in +\fBlzc_snaprange_space()\fR when \fI*usedp\fR was NULL. These issues were +rectified when the man page was written. + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/man/man3/lzc_snapshot.3 b/man/man3/lzc_snapshot.3 new file mode 100644 index 000000000000..3a0ea0665433 --- /dev/null +++ b/man/man3/lzc_snapshot.3 @@ -0,0 +1,174 @@ +'\" t +.\" +.\" CDDL HEADER START +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.\" CDDL HEADER END +.\" +.\" +.\" Copyright 2015 ClusterHQ Inc. All rights reserved. +.\" +.TH lzc_snapshot 3 "2015 JUL 8" "OpenZFS" "OpenZFS Programmer's Manual" + +.SH PROLOG +This manual page is part of the OpenZFS Programmer's Manual. + +.SH SYNOPSIS +#include + +\fBint\fR \fBlzc_snapshot\fR(\fBnvlist_t *\fR\fIsnaps\fR, \fBnvlist_t +*\fR\fIprops\fR, \fBnvlist_t **\fR\fIerrlist\fR); + +.SH NAME +lzc_snapshot \- Creates a snapshot of a dataset or volume + +.SH DESCRIPTION +.LP +The \fBlzc_snapshot\fR() function creates atomic snapshots of all ZFS +datasets and/or volumes named in the \fIsnaps\fR nvlist. + +.I snaps +shall be a nvlist containing strings that specify the snapshots to create. All snapshot smust be inside the same pool. + +.I props +shall either be NULL or contain a nvlist with properties to set on the snapshot +at creation time. Currently only user properties are supported. It shall be of +the format: +.sp +{ user:prop_name -> string value } + +.I errlist +shall contain a handle that shall be used to store a pointer to a library +allocated nvlist when non-NULL and the operation for at least one hold fails. +The names of the holds shall be the keys while the values shall contain the +error codes and be of type int32. Holds that failed to release because they did +not exist shall also have an entry added. It shall not be touched otherwise. + +.SH RETURN VALUES +.sp +.LP +Upon successful completion, 0 is returned. Otherwise, an error is returned. +.sp +On error, an error is returned from one of the holds where an error occurred +and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific +information when \fIerrlist\fR is non-NULL. The caller must call +\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. + +.SH ERRORS +.sp +.LP +The \fBlzc_snapshot()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBE2BIG\fR\fR +.ad +.RS 13n +The length of a property value is larger than 8191 characters excluding the +NULL termination character. +.RE + +.sp +.ne 2 +.na +\fB\fBEEXIST\fR\fR +.ad +.RS 13n +The pool was uninitialized and a pool with the same GUID already existed. +.sp +A snapshot with a name specified in \fIsnaps\fR already exists. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 13n +A property name in the \fIprops\fR nvlist is invalid. +.sp +\fIsnaps\fR is not a valid nvlist. +.sp +\fIprops\fR is not a valid nvlist. +.RE + +.sp +.ne 2 +.na +\fB\fBENAMETOOLONG\fR\fR +.ad +.RS 13n +A snapshot name in the \fIsnaps\fR nvlist exceeds 256 characters. +.sp +A property name in \fIprops\fR nvlist exceeds 256 characters. +.RE + +.sp +.ne 2 +.na +\fB\fBENOENT\fR\fR +.ad +.RS 13n +Pool does not exist. +.sp +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +.sp +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. +.sp +A dataset or volume specified in \fIsnaps\fR does not exist. +.RE + +.sp +.ne 2 +.na +\fB\fBENOMEM\fR\fR +.ad +.RS 13n +Failed to allocate memory necessary to send \fIsnaps\fR or \fIprops\fR to the +kernel. +.RE + +.sp +.ne 2 +.na +\fB\fBENOTSUP\fR\fR +.ad +.RS 13n +User properties were specified on a pool that is newer than version 12. +.RE + +.sp +.ne 2 +.na +\fB\fBEPERM\fR\fR +.ad +.RS 13n +Permission denied by zone security policy. +.RE + +\fB\fBEXDEV\fR\fR +.ad +.RS 13n +Multiple pools specified +.sp +Multiple snapshots per filesystem specified. +.RE + +.SH SEE ALSO +.sp +.LP +\fBlibzfs_core.h\fR(3), \fBzfs\fR(8) diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index bac8048afcea..da6b0852ca6e 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -309,8 +309,9 @@ exit 0 %files -n libzfs2-devel %{_datadir}/pkgconfig/libzfs.pc %{_datadir}/pkgconfig/libzfs_core.pc -%{_libdir}/*.so %{_includedir}/* +%{_libdir}/*.so +%{_mandir}/man3/* %doc AUTHORS COPYRIGHT DISCLAIMER %doc OPENSOLARIS.LICENSE README.markdown From 92d9de97e2dfa73bcfc1be2c3a1c4c462ba3290a Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 13:25:14 -0400 Subject: [PATCH 28/40] nvpair: expand fnvpair_pack encoding options Most fnvpair_pack is refactored to fnvpair_pack_enc which adds an encoding argument. fnvpair_pack is kept for backwards compatibility. Signed-off-by: Manuel Mendez --- include/sys/nvpair.h | 1 + module/nvpair/fnvpair.c | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/sys/nvpair.h b/include/sys/nvpair.h index d2dfad5ca2b3..9c358c0af920 100644 --- a/include/sys/nvpair.h +++ b/include/sys/nvpair.h @@ -281,6 +281,7 @@ nvlist_t *fnvlist_alloc(void); void fnvlist_free(nvlist_t *); size_t fnvlist_size(nvlist_t *); char *fnvlist_pack(nvlist_t *, size_t *); +char *fnvlist_pack_xdr(nvlist_t *, size_t *); void fnvlist_pack_free(char *, size_t); nvlist_t *fnvlist_unpack(char *, size_t); nvlist_t *fnvlist_dup(nvlist_t *); diff --git a/module/nvpair/fnvpair.c b/module/nvpair/fnvpair.c index a91b9524d8a0..1f436d627ccd 100644 --- a/module/nvpair/fnvpair.c +++ b/module/nvpair/fnvpair.c @@ -74,14 +74,44 @@ fnvlist_size(nvlist_t *nvl) * fnvlist_pack_free(). */ char * -fnvlist_pack(nvlist_t *nvl, size_t *sizep) +fnvlist_pack_enc(nvlist_t *nvl, size_t *sizep, int encoding) { char *packed = 0; - VERIFY3U(nvlist_pack(nvl, &packed, sizep, NV_ENCODE_NATIVE, + VERIFY3U(nvlist_pack(nvl, &packed, sizep, encoding, KM_SLEEP), ==, 0); return (packed); } +/* + * Returns allocated buffer of size *sizep. Caller must free the buffer with + * fnvlist_pack_free(). An alias for fnvlist_pacn_native. + */ +char * +fnvlist_pack(nvlist_t *nvl, size_t *sizep) +{ + return fnvlist_pack_native(nvl, sizep); +} + +/* + * Returns allocated buffer of size *sizep. Caller must free the buffer with + * fnvlist_pack_free(). Allocated buffer is native encoded. + */ +char * +fnvlist_pack_native(nvlist_t *nvl, size_t *sizep) +{ + return fnvlist_pack_enc(nvl, sizep, NV_ENCODE_NATIVE); +} + +/* + * Returns allocated buffer of size *sizep. Caller must free the buffer with + * fnvlist_pack_free(). Allocated buffer is XDR encoded. + */ +char * +fnvlist_pack_xdr(nvlist_t *nvl, size_t *sizep) +{ + return fnvlist_pack_enc(nvl, sizep, NV_ENCODE_XDR); +} + /*ARGSUSED*/ void fnvlist_pack_free(char *pack, size_t size) @@ -514,6 +544,7 @@ EXPORT_SYMBOL(fnvlist_alloc); EXPORT_SYMBOL(fnvlist_free); EXPORT_SYMBOL(fnvlist_size); EXPORT_SYMBOL(fnvlist_pack); +EXPORT_SYMBOL(fnvlist_pack_xdr); EXPORT_SYMBOL(fnvlist_pack_free); EXPORT_SYMBOL(fnvlist_unpack); EXPORT_SYMBOL(fnvlist_dup); From 240569b95c60e6aecbd2b4fdeec75587b04fa362 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 13:25:25 -0400 Subject: [PATCH 29/40] lzc: pack nvlist using XDR encoding Signed-off-by: Manuel Mendez --- lib/libzfs_core/libzfs_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 3d97619f1282..e7523667f448 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -130,7 +130,7 @@ lzc_ioctl_impl(zfs_ioc_t ioc, const char *name, if (name) (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); - packed = fnvlist_pack(source, &size); + packed = fnvlist_pack_xdr(source, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; From 5d79da221d0efa5b6708e8feb517bc0e8a363a2f Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 15:15:59 -0400 Subject: [PATCH 30/40] zfs: expand put_nvlist encoding options Signed-off-by: Manuel Mendez --- module/zfs/zfs_ioctl.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index bb2e54ef5a12..53b13b8b72f2 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -1420,7 +1420,7 @@ nvlist_smush(nvlist_t *errors, size_t max) } static int -put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) +put_nvlist_enc(zfs_cmd_t *zc, nvlist_t *nvl, int encoding) { char *packed = NULL; int error = 0; @@ -1431,7 +1431,7 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) if (size > zc->zc_nvlist_dst_size) { error = SET_ERROR(ENOMEM); } else { - packed = fnvlist_pack(nvl, &size); + packed = fnvlist_pack_enc(nvl, &size, encoding); if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0) error = SET_ERROR(EFAULT); @@ -1444,6 +1444,24 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) return (error); } +static int +put_nvlist_native(zfs_cmd_t *zc, nvlist_t *nvl) +{ + return put_nvlist_enc(zc, nvl, NV_ENCODE_NATIVE); +} + +static int +put_nvlist_xdr(zfs_cmd_t *zc, nvlist_t *nvl) +{ + return put_nvlist_enc(zc, nvl, NV_ENCODE_XDR); +} + +static int +put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) +{ + return put_nvlist_native(zc, nvl); +} + static int get_zfs_sb(const char *dsname, zfs_sb_t **zsbp) { From 3ca826d7643c2a741a4fd627882ff3295fbee967 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 15:19:33 -0400 Subject: [PATCH 31/40] zfs: use put_nvlist_xdr when encoding stable ioctl outnvl Signed-off-by: Manuel Mendez --- module/zfs/zfs_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 53b13b8b72f2..dd4db3439145 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -6556,7 +6556,7 @@ zfs_ioc_stable(zfs_cmd_t *zc) zc->zc_nvlist_dst_size); } if (smusherror == 0) - puterror = put_nvlist(zc, outnvl); + puterror = put_nvlist_xdr(zc, outnvl); } if (puterror != 0) From 681f57e573b2cdfe3379947880f9ede5ff519e9d Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 16:45:06 -0400 Subject: [PATCH 32/40] man: change man page layout to facilitate minimal diffs Signed-off-by: Manuel Mendez --- include/sys/nvpair.h | 4 +- man/man3/libzfs_core.h.3 | 7 +- man/man3/libzfs_core_init.3 | 17 ++-- man/man3/lzc_bookmark.3 | 32 +++--- man/man3/lzc_clone.3 | 12 ++- man/man3/lzc_create.3 | 9 +- man/man3/lzc_destroy_bookmarks.3 | 18 ++-- man/man3/lzc_destroy_one.3 | 23 ++--- man/man3/lzc_destroy_snaps.3 | 30 ++---- man/man3/lzc_exists.3 | 9 +- man/man3/lzc_get_bookmarks.3 | 23 +++-- man/man3/lzc_get_holds.3 | 27 ++--- man/man3/lzc_hold.3 | 45 ++++---- man/man3/lzc_inherit.3 | 8 +- man/man3/lzc_list.3 | 169 +++++++++++++------------------ man/man3/lzc_promote.3 | 29 +++--- man/man3/lzc_receive.3 | 42 ++++---- man/man3/lzc_rename.3 | 33 +++--- man/man3/lzc_rollback.3 | 10 +- man/man3/lzc_send.3 | 45 ++++---- man/man3/lzc_send_progress.3 | 10 +- man/man3/lzc_send_space.3 | 15 ++- man/man3/lzc_set_props.3 | 24 +++-- man/man3/lzc_snaprange_space.3 | 23 ++--- man/man3/lzc_snapshot.3 | 39 ++++--- module/nvpair/fnvpair.c | 22 ++-- 26 files changed, 315 insertions(+), 410 deletions(-) diff --git a/include/sys/nvpair.h b/include/sys/nvpair.h index 9c358c0af920..580fc1f8f2d3 100644 --- a/include/sys/nvpair.h +++ b/include/sys/nvpair.h @@ -280,8 +280,10 @@ int nvpair_value_double(nvpair_t *, double *); nvlist_t *fnvlist_alloc(void); void fnvlist_free(nvlist_t *); size_t fnvlist_size(nvlist_t *); -char *fnvlist_pack(nvlist_t *, size_t *); +char *fnvlist_pack_enc(nvlist_t *, size_t *, int); +char *fnvlist_pack_native(nvlist_t *, size_t *); char *fnvlist_pack_xdr(nvlist_t *, size_t *); +char *fnvlist_pack(nvlist_t *, size_t *); void fnvlist_pack_free(char *, size_t); nvlist_t *fnvlist_unpack(char *, size_t); nvlist_t *fnvlist_dup(nvlist_t *); diff --git a/man/man3/libzfs_core.h.3 b/man/man3/libzfs_core.h.3 index f126bbd451b7..8ba1f0fe93d7 100644 --- a/man/man3/libzfs_core.h.3 +++ b/man/man3/libzfs_core.h.3 @@ -25,10 +25,9 @@ .TH libzfs_core.h 3 "2015 JUL 3" "OpenZFS" "OpenZFS Programmer's Manual" .SH PROLOG -This manual page is part of the OpenZFS Programmer's Manual. The location of -the header might vary on different systems. Compilation with GCC on Linux -systems requires the addition of -I/usr/include/libspl -I/usr/include/libzfs to -GCC's parameters to include the proper headers. +This manual page is part of the OpenZFS Programmer's Manual. +The location of the header might vary on different systems. +Compilation with GCC on Linux systems requires the addition of -I/usr/include/libspl -I/usr/include/libzfs to GCC's parameters to include the proper headers. .SH NAME libzfs_core.h \- Stable OpenZFS Management C API diff --git a/man/man3/libzfs_core_init.3 b/man/man3/libzfs_core_init.3 index 0c5ce4a18ae2..e9c6dd237b82 100644 --- a/man/man3/libzfs_core_init.3 +++ b/man/man3/libzfs_core_init.3 @@ -38,26 +38,23 @@ libzfs_core_init, libzfs_core_fini \- Initialize and deinitialize libzfs_core li .SH DESCRIPTION .LP -The -\fBlibzfs_core_init\fR() -function is a singleton constructor for the libzfs_core library. It should be called once at program initialization. Multiple calls to -\fBlibzfs_core_init\fR() -are fine provided that they be matched by an equal number of alls to the -\fBlibzfs_core_fini\fR() -function. +The \fBlibzfs_core_init\fR() function is a singleton constructor for the libzfs_core library. +It should be called once at program initialization. +Multiple calls to \fBlibzfs_core_init\fR() are fine provided that they be matched by an equal number of alls to the \fBlibzfs_core_fini\fR() function. .SH RETURN VALUES .sp .LP -Upon successful completion of the \fBlibzfs_core_init\fR() function, 0 is returned and a file descriptor is open for /dev/zfs. Otherwise, an error is returned. +Upon successful completion of the \fBlibzfs_core_init\fR() function, 0 is returned and a file descriptor is open for /dev/zfs. +Otherwise, an error is returned. .sp The \fBlibzfs_core_fini\fR() function returns no value and does not fail. .BR .SH ERRORS .sp .LP -The \fBlibzfs_core_init\fR() function shall fail if \fBopen\fR(2) of /dev/zfs -fails. In this situation, the error code from \fBopen\fR(2) will be returned. +The \fBlibzfs_core_init\fR() function shall fail if \fBopen\fR(2) of /dev/zfs fails. +In this situation, the error code from \fBopen\fR(2) will be returned. .SH "SEE ALSO" .sp diff --git a/man/man3/lzc_bookmark.3 b/man/man3/lzc_bookmark.3 index 60e5f52eb681..428ce0bead9d 100644 --- a/man/man3/lzc_bookmark.3 +++ b/man/man3/lzc_bookmark.3 @@ -30,38 +30,33 @@ This manual page is part of the OpenZFS Programmer's Manual. .SH SYNOPSIS #include -\fBint\fR \fBlzc_bookmark\fR(\fBnvlist_t *\fR\fIbookmarks\fR, \fBnvlist_t -**\fR\fIerrlist\fR); +\fBint\fR \fBlzc_bookmark\fR(\fBnvlist_t *\fR\fIbookmarks\fR, \fBnvlist_t **\fR\fIerrlist\fR); .SH NAME lzc_bookmark \- Creates bookmarks from snapshot .SH DESCRIPTION .LP -The \fBlibzfs_snapshot\fR() function creates atomic snapshots of all ZFS -datasets and/or volumes named in the \fIsnaps\fR nvlist. +The \fBlibzfs_snapshot\fR() function creates atomic snapshots of all ZFS datasets and/or volumes named in the \fIsnaps\fR nvlist. .I bookmarks -shall be a nvlist containing strings whose keys are bookmark names and values -are snapshot names to specify which bookmarks to create. All bookmarks and -snapshots must be inside the same pool. +shall be a nvlist containing strings whose keys are bookmark names and values are snapshot names to specify which bookmarks to create. +All bookmarks and snapshots must be inside the same pool. .I errlist -shall contain a handle that shall be used to store a pointer to a library -allocated nvlist when non-NULL and the operation for at least one hold fails. -The names of the holds shall be the keys while the values shall contain the -error codes and be of type int32. Holds that failed to release because they did -not exist shall also have an entry added. It shall not be touched otherwise. +shall contain a handle that shall be used to store a pointer to a library allocated nvlist when non-NULL and the operation for at least one hold fails. +The names of the holds shall be the keys while the values shall contain the error codes and be of type int32. +Holds that failed to release because they did not exist shall also have an entry added. +It shall not be touched otherwise. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .sp -On error, an error is returned from one of the holds where an error occurred -and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific -information when \fIerrlist\fR is non-NULL. The caller must call -\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. +On error, an error is returned from one of the holds where an error occurred and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific information when \fIerrlist\fR is non-NULL. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp @@ -123,8 +118,7 @@ A snapshot specified in \fIbookmarks\fR does not exist. \fB\fBENOMEM\fR\fR .ad .RS 13n -Failed to allocate memory necessary to send \fIbookmarks\fR to the -kernel. +Failed to allocate memory necessary to send \fIbookmarks\fR to the kernel. .RE .sp diff --git a/man/man3/lzc_clone.3 b/man/man3/lzc_clone.3 index 3347ce09bb2d..c28d3246f4a7 100644 --- a/man/man3/lzc_clone.3 +++ b/man/man3/lzc_clone.3 @@ -49,7 +49,8 @@ Properties may optionally be set using .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp .LP @@ -60,8 +61,7 @@ The \fBlzc_clone()\fR function will fail if: \fB\fBEDQUOT\fR\fR .ad .RS 13n -Creation of the clone will require storage space in excess of the filesystem -quota. +Creation of the clone will require storage space in excess of the filesystem quota. .RE .sp @@ -81,9 +81,11 @@ A dataset named \fIfsname\fR already exists. \fB\fBEINVAL\fR\fR .ad .RS 13n -The dataset name \fIfsname\fR is not syntactically correct. This includes situations where bookmarks, snapshots or holds are specified. +The dataset name \fIfsname\fR is not syntactically correct. +This includes situations where bookmarks, snapshots or holds are specified. .sp -The snapshot name \fIorigin\fR is not syntactically correct. This includes the case of attempting to clone a non-snapshot. +The snapshot name \fIorigin\fR is not syntactically correct. +This includes the case of attempting to clone a non-snapshot. .sp The nvlist_t \fIprops\fR could not be understood by the kernel as being NULL or a nvlist. .RE diff --git a/man/man3/lzc_create.3 b/man/man3/lzc_create.3 index 72c44a1f7432..7bedb16d4bf0 100644 --- a/man/man3/lzc_create.3 +++ b/man/man3/lzc_create.3 @@ -37,15 +37,14 @@ lzc_create \- Create a ZFS dataset or volume .SH DESCRIPTION .LP -The -\fBlibzfs_create\fR() -function creates a dataset or zvol according to \fItype\fR. Optional properties -are passed through \fIprops\fR. +The \fBlibzfs_create\fR() function creates a dataset or zvol according to \fItype\fR. +Optional properties are passed through \fIprops\fR. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp diff --git a/man/man3/lzc_destroy_bookmarks.3 b/man/man3/lzc_destroy_bookmarks.3 index 65a54c24093b..7f7cc165a8a9 100644 --- a/man/man3/lzc_destroy_bookmarks.3 +++ b/man/man3/lzc_destroy_bookmarks.3 @@ -37,12 +37,10 @@ lzc_destroy_bookmarks \- Destroys bookmarks .SH DESCRIPTION .LP -The \fBlzc_destroy_bookmarks\fR() function shall atomically destroy bookmarks -specified within a pool. The pool is determined implicitly from the list of -bookmarks. If \fIerrlist\fR is specified and destruction of a bookmark fails -(e.g. specified name too long), it will be allocated and updated to contain a -list of bookmarks where the operation failed. The keys of the list will be the -full bookmark names while the values will be int32 error codes. +The \fBlzc_destroy_bookmarks\fR() function shall atomically destroy bookmarks specified within a pool. +The pool is determined implicitly from the list of bookmarks. +If \fIerrlist\fR is specified and destruction of a bookmark fails (e.g. specified name too long), it will be allocated and updated to contain a list of bookmarks where the operation failed. +The keys of the list will be the full bookmark names while the values will be int32 error codes. .sp Bookmarks that do not exist will be silently ignored. @@ -51,11 +49,9 @@ Bookmarks that do not exist will be silently ignored. .LP Upon successful completion, 0 is returned. .sp -On error, an error is returned from one of the bookmarks where an error -occurred and \fIerrlist\fR is populated with more specific information if a -pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names -and int32 values of the error codes. The caller must call \fBnvlist_free\fR() -on \fIerrlist\fR if this occurs. +On error, an error is returned from one of the bookmarks where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. +\fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. +The caller must call \fBnvlist_free\fR() on \fIerrlist\fR if this occurs. .SH ERRORS .sp .LP diff --git a/man/man3/lzc_destroy_one.3 b/man/man3/lzc_destroy_one.3 index d55cec41992b..79f6bbd813b6 100644 --- a/man/man3/lzc_destroy_one.3 +++ b/man/man3/lzc_destroy_one.3 @@ -38,24 +38,22 @@ lzc_destroy_one \- Destroys a dataset or volume .SH DESCRIPTION .LP The \fBlzc_destroy_one\fR() function shall destroys a dataset or a volume. -Destroying snapshots and bookmarks is not currently supported. Call -lzc_destroy_snaps and lzc_destroy_bookmarks for those respectively. +Destroying snapshots and bookmarks is not currently supported. +Call lzc_destroy_snaps and lzc_destroy_bookmarks for those respectively. -The only currently valid property is the boolean "defer". It makes destruction -asynchronous such that the only error code back is if we try to destroy -something that does not exist. The caller must unmount the dataset before -calling this. Otherwise, it will fail. +The only currently valid property is the boolean "defer". +It makes destruction asynchronous such that the only error code back is if we try to destroy something that does not exist. +The caller must unmount the dataset before calling this. +Otherwise, it will fail. .SH RETURN VALUES .sp .LP Upon successful completion, 0 is returned. .sp -On error, an error is returned from one of the bookmarks where an error -occurred and \fIerrlist\fR is populated with more specific information if a -pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names -and int32 values of the error codes. The caller must call \fBnvlist_free\fR() -on \fIerrlist\fR if this occurs. +On error, an error is returned from one of the bookmarks where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. +\fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. +The caller must call \fBnvlist_free\fR() on \fIerrlist\fR if this occurs. .SH ERRORS .sp .LP @@ -66,8 +64,7 @@ The \fBlzc_destroy_one()\fR function will fail if: \fB\fBEBUSY\fR\fR .ad .RS 13n -Dataset named \fIdataset\fR has a long hold from a zfs send stream or a user -hold from \fBlzc_hold\fR(). +Dataset named \fIdataset\fR has a long hold from a zfs send stream or a user hold from \fBlzc_hold\fR(). .RE .sp diff --git a/man/man3/lzc_destroy_snaps.3 b/man/man3/lzc_destroy_snaps.3 index 99cbffd6053d..83b23514c5c9 100644 --- a/man/man3/lzc_destroy_snaps.3 +++ b/man/man3/lzc_destroy_snaps.3 @@ -37,31 +37,24 @@ lzc_destroy_snaps \- Destroy snapshots .SH DESCRIPTION .LP -The \fBlzc_destroy_snaps\fR() function destroys snapshots specified via strings -through the nvlist \fRsnaps\fR. They must all be in the same pool. +The \fBlzc_destroy_snaps\fR() function destroys snapshots specified via strings through the nvlist \fRsnaps\fR. +They must all be in the same pool. .sp Snapshots that do not exist will be silently ignored. .sp -If \fIdefer\fR is not set, and a snapshot has user holds or clones, the -destroy operation will fail and none of the snapshots will be -destroyed. +If \fIdefer\fR is not set, and a snapshot has user holds or clones, the destroy operation will fail and none of the snapshots will be destroyed. .sp -If \fIdefer\fR is set, and a snapshot has user holds or clones, it will be -marked for deferred destruction, and will be destroyed when the last hold -or clone is removed/destroyed. +If \fIdefer\fR is set, and a snapshot has user holds or clones, it will be marked for deferred destruction, and will be destroyed when the last hold or clone is removed/destroyed. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. This means that all snapshots were -destroyed (excluding those that did not exist) or were marked for later -distruction if \fIdefer\fR is set. -.sp -On error, an error is returned from one of the snapshots where an error -occurred and \fIerrlist\fR is populated with more specific information if a -pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names -and int32 values of the error codes. The caller must call \fBnvlist_free\fR() -on \fIerrlist\fR if this occurs. +Upon successful completion, 0 is returned. +This means that all snapshots were destroyed (excluding those that did not exist) or were marked for later distruction if \fIdefer\fR is set. +.sp +On error, an error is returned from one of the snapshots where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. +\fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. +The caller must call \fBnvlist_free\fR() on \fIerrlist\fR if this occurs. .SH ERRORS .sp .LP @@ -76,8 +69,7 @@ Snapshot held by a user hold and \fIdefer\fR is not specified. .sp Snapshot held by a zfs send stream and \fIdefer\fR is not specified. .sp -Snapshot held by an open file hanle or program's present working directory and -\fIdefer\fR is not specified. +Snapshot held by an open file hanle or program's present working directory and \fIdefer\fR is not specified. .RE .sp diff --git a/man/man3/lzc_exists.3 b/man/man3/lzc_exists.3 index 97bd8ed71fe0..3d3227b91703 100644 --- a/man/man3/lzc_exists.3 +++ b/man/man3/lzc_exists.3 @@ -41,7 +41,8 @@ The \fBlzc_exists\fR() function tests whether .I dataset -exists. It is more efficient than calling +exists. +It is more efficient than calling \fBlzc_list\fR(), but it does not apply to bookmarks. @@ -54,13 +55,13 @@ function returns a 0 (B_TRUE) when .I dataset exists and 1 (B_FALSE) when .I dataset -does not exist. On failure, the function returns an error code. +does not exist. +On failure, the function returns an error code. .SH ERRORS .sp .LP -The \fBlzc_exists()\fR function should never return an error when the library -has been properly initialized. +The \fBlzc_exists()\fR function should never return an error when the library has been properly initialized. .SH SEE ALSO .sp diff --git a/man/man3/lzc_get_bookmarks.3 b/man/man3/lzc_get_bookmarks.3 index b15b0485423c..12d7419e99f9 100644 --- a/man/man3/lzc_get_bookmarks.3 +++ b/man/man3/lzc_get_bookmarks.3 @@ -25,8 +25,8 @@ .TH lzc_get_boomarks 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" .SH PROLOG -This manual page is part of the OpenZFS Programmer's Manual. The location of -the header might vary on different systems. +This manual page is part of the OpenZFS Programmer's Manual. +The location of the header might vary on different systems. .SH SYNOPSIS #include @@ -38,11 +38,10 @@ lzc_get_bookmarks \- Retrieve bookmarks of a given filesystem .SH DESCRIPTION .LP -The \fBlzc_get_bookmarks\fR() function will retrieve the list of bookmarks for -the given file system. The \fIprops\fR parameter is an nvlist of property names -(with no values) that will be returned for each bookmark. The \fIbmarks\fR -parameter is a pointer to a nvlist of the bookmarks. The caller is responsible -for freeing it with \fBnvlist_free\fR(). +The \fBlzc_get_bookmarks\fR() function will retrieve the list of bookmarks for the given file system. +The \fIprops\fR parameter is an nvlist of property names (with no values) that will be returned for each bookmark. +The \fIbmarks\fR parameter is a pointer to a nvlist of the bookmarks. +The caller is responsible for freeing it with \fBnvlist_free\fR(). The format of the returned nvlist as follows: .P @@ -53,8 +52,8 @@ The format of the returned nvlist as follows: .br } -The following are valid properties on bookmarks. All of them are uint64 values -in the nvlist: +The following are valid properties on bookmarks. +All of them are uint64 values in the nvlist: .sp .na \fB\fBguid\fR\fR @@ -82,7 +81,8 @@ Unsupported properties will be silently ignored. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp @@ -156,7 +156,8 @@ Permission denied by zone security policy. \fB\fBESRCH\fR\fR .ad .RS 13n -A specified, but valid, bookmark was not found. This merits a bug report. +A specified, but valid, bookmark was not found. +This merits a bug report. .RE .SH SEE ALSO diff --git a/man/man3/lzc_get_holds.3 b/man/man3/lzc_get_holds.3 index 80f72ddd37b9..f195be6b9252 100644 --- a/man/man3/lzc_get_holds.3 +++ b/man/man3/lzc_get_holds.3 @@ -38,14 +38,12 @@ lzc_get_holds \- Retrieve list of user holds on the specified snapshot. .SH DESCRIPTION .LP The \fBlzc_get_holds\fR() function returns a nvlist of holds on the snapshot. -The nvlist keys will be the short names of the holds while the nvlist values -will be uint64 numbers. The numbers are internal identifiers that have no -application to userland in the current iteration of the libzfs_core API. +The nvlist keys will be the short names of the holds while the nvlist values will be uint64 numbers. +The numbers are internal identifiers that have no application to userland in the current iteration of the libzfs_core API. .SH RETURN VALUE -On success, the \fBlzc_get_holds\fR() function returns 0 and fills in -\fI*holdsp\fR when \fIholdsp\R is non-NULL. On failure, the function returns an -error code. +On success, the \fBlzc_get_holds\fR() function returns 0 and fills in \fI*holdsp\fR when \fIholdsp\R is non-NULL. +On failure, the function returns an error code. .SH ERRORS .BR lzc_get_holds () @@ -53,18 +51,17 @@ can fail with the following errors: .TP .B ENOENT -Pool does not exist, or if unintialized, the cachefile is out of -sync because loading the pool failed due to an exported or -destroyed pool. If pool exists, snapshot does not exist. +Pool does not exist, or if unintialized, the cachefile is out of sync because loading the pool failed due to an exported or destroyed pool. +If pool exists, snapshot does not exist. .TP .B EEXIST -The pool was uninitialized and a pool with the same GUID already -existed. +The pool was uninitialized and a pool with the same GUID already existed. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp @@ -105,11 +102,9 @@ The string \fIsnapname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or -destroyed. +Loading unitialized pool from cachefile failed because the pool was exported or destroyed. .sp -Internal error where uninitialized pool lacks a GUID in its config that was -read from the cachefile. +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp The snapshot \fIsnapname\fR does not exist. .RE diff --git a/man/man3/lzc_hold.3 b/man/man3/lzc_hold.3 index 388772e26e3b..0de01934f10f 100644 --- a/man/man3/lzc_hold.3 +++ b/man/man3/lzc_hold.3 @@ -40,46 +40,36 @@ lzc_hold, lzc_release \- Creates and releases user holds on snapshots .SH DESCRIPTION .LP -The \fBlzc_hold\fR() function creates user holds on snapshots. If there is a -hold on a snapshot, the snapshot can not be destroyed. +The \fBlzc_hold\fR() function creates user holds on snapshots. +If there is a hold on a snapshot, the snapshot can not be destroyed. .sp -However, it can be marked for deletion by calling \fBlzc_destroy_snaps\fR() -with defer=B_TRUE. Snapshots preserved in the way shall be destroyed as the -user hold is removed. +However, it can be marked for deletion by calling \fBlzc_destroy_snaps\fR() with defer=B_TRUE. +Snapshots preserved in the way shall be destroyed as the user hold is removed. .sp -\fBlzc_release\fR() shall explicitly release a hold. If the snapshot has been -marked for deferred destroy by calling \fBlzc_destroy_snaps\fR() with -defer=B_TRUE, it does not have any clones, and all the user holds are removed, -then the snapshot shall be destroyed. +\fBlzc_release\fR() shall explicitly release a hold. +If the snapshot has been marked for deferred destroy by calling \fBlzc_destroy_snaps\fR() with defer=B_TRUE, it does not have any clones, and all the user holds are removed, then the snapshot shall be destroyed. .I snaps -shall be a nvlist with zfs snapshots to hold to hold. It shall store string -keys that are the snapshots and values that are the hold names. +shall be a nvlist with zfs snapshots to hold to hold. +It shall store string keys that are the snapshots and values that are the hold names. .I cleanup_fd -shall be a file descriptor that specifies thta the hold is temporary and is to -be closed when the specified file descriptor is closed. Specifying the file -descriptor 0 disables this behavior while specifying the file descriptor -1 -shall make the hold close when the file descriptor for /dev/zfs held by the -library is closed. +shall be a file descriptor that specifies thta the hold is temporary and is to be closed when the specified file descriptor is closed. +Specifying the file descriptor 0 disables this behavior while specifying the file descriptor -1 shall make the hold close when the file descriptor for /dev/zfs held by the library is closed. .I errlist -shall contain a handle that shall be used to store a pointer to a library -allocated nvlist when non-NULL and the operation for at least one hold fails. -The names of the holds shall be the keys while the values shall contain the -error codes and be of type int32. Holds that failed to release because they -did not exist shall also have an entry added. It shall not be touched -otherwise. +shall contain a handle that shall be used to store a pointer to a library allocated nvlist when non-NULL and the operation for at least one hold fails. +The names of the holds shall be the keys while the values shall contain the error codes and be of type int32. +Holds that failed to release because they did not exist shall also have an entry added. +It shall not be touched otherwise. .SH RETURN VALUES .sp .LP Upon successful completion, 0 is returned. .sp -On error, an error is returned from one of the holds where an error occurred -and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific -information when \fIerrlist\fR is non-NULL. The caller must call -\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. +On error, an error is returned from one of the holds where an error occurred and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific information when \fIerrlist\fR is non-NULL. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp @@ -91,8 +81,7 @@ The \fBlzc_hold()\fR function shall fail if: \fB\fBE2BIG\fR\fR .ad .RS 13n -The hold short name exceeds 256 or 238 in the case of a temporary -hold. +The hold short name exceeds 256 or 238 in the case of a temporary hold. .RE .sp diff --git a/man/man3/lzc_inherit.3 b/man/man3/lzc_inherit.3 index 96d9c9d0def1..1a5ef3468acd 100644 --- a/man/man3/lzc_inherit.3 +++ b/man/man3/lzc_inherit.3 @@ -37,15 +37,13 @@ lzc_inherit \- Reset dataset property to default value .SH DESCRIPTION .LP -The -\fBlzc_inherit\fR() -function shall atomically reset property \fIpropname\fR of dataset -\fIfsname\fR. +The \fBlzc_inherit\fR() function shall atomically reset property \fIpropname\fR of dataset \fIfsname\fR. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp .LP diff --git a/man/man3/lzc_list.3 b/man/man3/lzc_list.3 index 8fbc02d181d1..a473d9a72b70 100644 --- a/man/man3/lzc_list.3 +++ b/man/man3/lzc_list.3 @@ -37,18 +37,17 @@ lzc_list \- List filesystems, volumes, snapshots and bookmarks .SH DESCRIPTION .LP -The \fBlzc_list\fR() function writes a series of records to the output method -specified in the nvlist \fIopts\fR. It is designed to provide a large subset of -the functionality of the \fBzfs list\fR subcommand and operates similarly to -it. At present, the only supported output method is an asynchronous file -descriptor. +The \fBlzc_list\fR() function writes a series of records to the output method specified in the nvlist \fIopts\fR. +It is designed to provide a large subset of the functionality of the \fBzfs list\fR subcommand and operates similarly to it. +At present, the only supported output method is an asynchronous file descriptor. .I name -The name of the pool, dataset, snapshot or volume to list by writing to fd. If -NULL, a description of all pools is written to fd. +The name of the pool, dataset, snapshot or volume to list by writing to fd. +If NULL, a description of all pools is written to fd. .I opts -A nvlist used to manipulate output. It takes these values: +A nvlist used to manipulate output. +It takes these values: .sp .in +2 .nf @@ -59,13 +58,12 @@ NAME TYPE DESCRIPTION .fi .in -2 .sp -At present, the fd field is the only supported output method and therefore, it -is mandatory. If the name field is a bookmark or snapshot, the recurse field -is ignored. If the passed name is that of a bookmark or snapshot, the recurse -field is ignored. If all children are desired, recurse should be set to be a -boolean type. If a recursion limit is desired, recurses hould be a uint64_t. If -no type is specified, a default behavior consistent with the zfs list command -is provided. Valid children of the type nvlist are: +At present, the fd field is the only supported output method and therefore, it is mandatory. +If the name field is a bookmark or snapshot, the recurse field is ignored. +If the passed name is that of a bookmark or snapshot, the recurse field is ignored. +If all children are desired, recurse should be set to be a boolean type. +If a recursion limit is desired, recurses hould be a uint64_t. +If no type is specified, a default behavior consistent with the zfs list command is provided. Valid children of the type nvlist are: .sp .in +2 .nf @@ -79,24 +77,17 @@ NAME TYPE DESCRIPTION .fi .in -2 .sp -Whenever a boolean type is specified, any type may be passed and be -considered boolean. However, future extensions may accept alternate types -and consequently, backward compatibility is only guarenteed to callers -passing a boolean type that contains no value. A boolean that contains -B_TRUE or B_FALSE is considered a separate type from a boolean that contains -no value. Additionally, future enhancements to zfs may create a new type and -callers that only wish to handle existing types should specify them -explicitly rather than relying on the default behavior. -.sp -The parent-child relationship is obeyed such all children of each -pool/directory are output alongside their parents. However, no guarantees -are made with regard to post-order/pre-order traversal or the order of -bookmarks/snapshots, such that the order is allowed to change. Userland -applications that are sensitive to a particular output order are expected to -sort. -.sp -The output consists of a record header followed immediately by XDR-encoded -nvlist. The header format is as follows: +Whenever a boolean type is specified, any type may be passed and be considered boolean. +However, future extensions may accept alternate types and consequently, backward compatibility is only guarenteed to callers passing a boolean type that contains no value. +A boolean that contains B_TRUE or B_FALSE is considered a separate type from a boolean that contains no value. +Additionally, future enhancements to zfs may create a new type and callers that only wish to handle existing types should specify them explicitly rather than relying on the default behavior. +.sp +The parent-child relationship is obeyed such all children of each pool/directory are output alongside their parents. +However, no guarantees are made with regard to post-order/pre-order traversal or the order of bookmarks/snapshots, such that the order is allowed to change. +Userland applications that are sensitive to a particular output order are expected to sort. +.sp +The output consists of a record header followed immediately by XDR-encoded nvlist. +The header format is as follows: .sp .in +2 .nf @@ -109,23 +100,14 @@ OFFSET SIZE DESCRIPTION .fi .in -2 .sp -Errors obtaining information for any record will be contained in the return -code. The output for any record whose header return code contains an error -is a XDR encoded nvlist whose contents are undefined, unless the size -provided in the header is zero, in which case the output for that record is -empty. The receiver is expected to check the endian bit field before -processing the XDR-nvlist size and perform a byte-swap operation on the -value should the endian-ness differ. -.sp -Non-zero values in the reserved field and upper bits of the endian field -imply a back-incompatible change. If the header extension field is non-zero -when neither the reserved field nor the upper bits of the endian field are -non-zero, the header should be assumed to have been extended in a -backward-compatible way and the XDR-nvlist of the specified size shall -follow the extended header. The lzc_list() library call will always request -API version 0 request as part of the ioctl to userland. Consequently, the -kernel will return an API version 0 compatible-stream unless a change is -requested via a future extension to the opts nvlist. +Errors obtaining information for any record will be contained in the return code. +The output for any record whose header return code contains an error is a XDR encoded nvlist whose contents are undefined, unless the size provided in the header is zero, in which case the output for that record is empty. +The receiver is expected to check the endian bit field before processing the XDR-nvlist size and perform a byte-swap operation on the value should the endian-ness differ. +.sp +Non-zero values in the reserved field and upper bits of the endian field imply a back-incompatible change. +If the header extension field is non-zero when neither the reserved field nor the upper bits of the endian field are non-zero, the header should be assumed to have been extended in a backward-compatible way and the XDR-nvlist of the specified size shall follow the extended header. +The lzc_list() library call will always request API version 0 request as part of the ioctl to userland. +Consequently, the kernel will return an API version 0 compatible-stream unless a change is requested via a future extension to the opts nvlist. .sp The nvlist will have the following members: .sp @@ -157,8 +139,9 @@ NAME TYPE DESCRIPTION .sp Additional members may be added in future extensions. .sp -The "dds_" prefix stands for "DSL Dataset". "dds_type" is a string -representation of internal object types. Valid values at this time are: +The "dds_" prefix stands for "DSL Dataset". +"dds_type" is a string representation of internal object types. +Valid values at this time are: .sp .in +2 .nf @@ -172,38 +155,30 @@ NAME PUBLIC DESCRIPTION .fi .in -2 .sp -Only the public values will be returned for any output. The return of a -value not on this list implies a record for a new storage type. The output -should be consistent with existing types and the receiver can elect to -either handle it in a manner consistent with existing types or skip it. -Under no circumstance will an unlisted type be returned when types were -explicitly provided via the opts nvlist. -.sp -On bookmarks, the "dmu_objset_stats" of the parent DSL Dataset shall be -returned. Consequently, "dds_is_snapshot" shall be false and identification -of bookmarks shall be done by checking for the '#' character in the "name" -member of the top level nvlist. This is done so that the type of the -bookmarked DSL dataset may be known. -.sp -End of output shall be signified by NULL record header. Userland is expected -to close the file descriptor. Early termination can be signaled from -userland by closing the file descriptor. -.sp -The design of the output is intended to enable userland to perform readahead -on the file descriptor. On certain platforms, libc may provide output -buffering. Userland libraries and applications electing to perform readahead -should take care not to block on a partially filled buffer when an end of -stream NULL record is returned. +Only the public values will be returned for any output. +The return of a value not on this list implies a record for a new storage type. +The output should be consistent with existing types and the receiver can elect to either handle it in a manner consistent with existing types or skip it. +Under no circumstance will an unlisted type be returned when types were explicitly provided via the opts nvlist. +.sp +On bookmarks, the "dmu_objset_stats" of the parent DSL Dataset shall be returned. +Consequently, "dds_is_snapshot" shall be false and identification of bookmarks shall be done by checking for the '#' character in the "name" member of the top level nvlist. +This is done so that the type of the bookmarked DSL dataset may be known. +.sp +End of output shall be signified by NULL record header. +Userland is expected to close the file descriptor. +Early termination can be signaled from userland by closing the file descriptor. +.sp +The design of the output is intended to enable userland to perform readahead on the file descriptor. +On certain platforms, libc may provide output buffering. +Userland libraries and applications electing to perform readahead.should take care not to block on a partially filled buffer when an end of stream NULL record is returned. .sp .SH RETURN VALUES .sp .LP Upon successful completion, 0 is returned. .sp -On error, an error is returned from one of the holds where an error occurred -and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific -information when \fIerrlist\fR is non-NULL. The caller must call -\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. +On error, an error is returned from one of the holds where an error occurred and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific information when \fIerrlist\fR is non-NULL. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp @@ -215,8 +190,8 @@ The \fBlzc_list()\fR function shall fail if: \fB\fBEAGAIN\fR\fR, \fB\fBEWOULDBLOCK\fR\fR .ad .RS 13n -The file descriptor was marked non-blocking and the call would block. This is -from \fBwrite\fR(2). +The file descriptor was marked non-blocking and the call would block. +This is from \fBwrite\fR(2). .RE .sp @@ -243,8 +218,8 @@ The file descriptor "\fIfd\fR" in the \fIopts\fR nvlist is invalid. \fB\fBEDESTADDRREQ\fR\fR .ad .RS 13n -The file descriptor is a datagram socket for which a peer address has not been -set using \fBconnect\fR(2). This is from \fBwrite\fR(2). +The file descriptor is a datagram socket for which a peer address has not been set using \fBconnect\fR(2). +This is from \fBwrite\fR(2). .RE .sp @@ -262,8 +237,8 @@ The pool was uninitialized and a pool with the same GUID already existed. \fB\fBEFAULT\fR\fR .ad .RS 13n -Internal issue occurred when copying command data from userland to kernel. See -Illumos ddi_copyin(9F). +Internal issue occurred when copying command data from userland to kernel. +See Illumos ddi_copyin(9F). .RE .sp @@ -272,8 +247,7 @@ Illumos ddi_copyin(9F). \fB\fBEFBIG\fR\fR .ad .RS 13n -The file descriptor \fIfd\fR in the \fIopts\fR nvlist is a file and writing to -it would cause it to exceed the maximum file size permitted by the filesystem. +The file descriptor \fIfd\fR in the \fIopts\fR nvlist is a file and writing to it would cause it to exceed the maximum file size permitted by the filesystem. This is from \fBwrite\fR(2). .RE @@ -283,7 +257,8 @@ This is from \fBwrite\fR(2). \fB\fBEIO\fR\fR .ad .RS 13n -A low level error occurred. This is from \fBwrite\fR(2). +A low level error occurred. +This is from \fBwrite\fR(2). .RE .sp @@ -334,8 +309,8 @@ Failed to allocate memory necessary to send \fIopts\fR to the kernel. \fB\fBENOSPC\fR\fR .ad .RS 13n -The file descriptor \fIfd\fR in the \fIopts\fR nvlist cannot be appended. This -is from \fBwrite\fR(2). +The file descriptor \fIfd\fR in the \fIopts\fR nvlist cannot be appended. +This is from \fBwrite\fR(2). .RE .sp @@ -344,8 +319,8 @@ is from \fBwrite\fR(2). \fB\fBEPIPE\fR\fR .ad .RS 13n -The file descriptor is a pipe whose reading end is closed. This is from -\fBwrite\fR(2). +The file descriptor is a pipe whose reading end is closed. +This is from \fBwrite\fR(2). .RE .sp @@ -359,14 +334,10 @@ Permission denied by zone security policy. .SH ERRATA Unlike other \fBlzc_*\fR() functions, the output of this function is non-atomic. -Consequently, rename, creation, destruction and property creation operations -can race with it. Avoiding this requires allowing userland to block the kernel -when it holds key locks required for the aforementioned operations, which is a -denial of service vulnerability. Userland consumers must handle edge cases -where concurrent operations cause the output to be inconsistent. One example is -that renames can cause datasets to appear twice (or not at all) depending on -what has been output and where the rename moves a dataset, volume, snapshot or -bookmark. +Consequently, rename, creation, destruction and property creation operations can race with it. +Avoiding this requires allowing userland to block the kernel when it holds key locks required for the aforementioned operations, which is a denial of service vulnerability. +Userland consumers must handle edge cases where concurrent operations cause the output to be inconsistent. +One example is that renames can cause datasets to appear twice (or not at all) depending on what has been output and where the rename moves a dataset, volume, snapshot or bookmark. .SH SEE ALSO .sp diff --git a/man/man3/lzc_promote.3 b/man/man3/lzc_promote.3 index 5a6d7a0c309d..bde99d39551d 100644 --- a/man/man3/lzc_promote.3 +++ b/man/man3/lzc_promote.3 @@ -37,29 +37,24 @@ lzc_promote \- Reverse clone parent-child relationship .SH DESCRIPTION .LP -The \fBlzc_promote\fR() function promotes a clone file system \fIfsname\fR to -no longer be dependent on its "origin" snapshot. This makes it possible to -destroy the file system from which the clone was created. The clone -parent-child dependency relationship is reversed, so that the origin file -system becomes a clone of the specified file system. +The \fBlzc_promote\fR() function promotes a clone file system \fIfsname\fR to no longer be dependent on its "origin" snapshot. +This makes it possible to destroy the file system from which the clone was created. +The clone parent-child dependency relationship is reversed, so that the origin file system becomes a clone of the specified file system. -The snapshot that was cloned, and any snapshots previous to this snapshot, are -now owned by the promoted clone. The space they use moves from the origin file -system to the promoted clone, so enough space must be available to accom‐ -modate these snapshots. No new space is consumed by this operation, but the -space accounting is adjusted. The promoted clone must not have any conflicting -snapshot names of its own. The rename subcommand can be used to rename any -conflicting snapshots. +The snapshot that was cloned, and any snapshots previous to this snapshot, are now owned by the promoted clone. +The space they use moves from the origin file system to the promoted clone, so enough space must be available to accommodate these snapshots. +No new space is consumed by this operation, but the space accounting is adjusted. +The promoted clone must not have any conflicting snapshot names of its own. +The rename subcommand can be used to rename any conflicting snapshots. -The nvlist \fIopts\fR is reserved for future extensions that provide options -that alter the behavior of the lzc_promote() function. At the time of writing, -all data passed to it is ignored and callers should pass NULL to ensure that -behavior remains the same with future extensions. +The nvlist \fIopts\fR is reserved for future extensions that provide options that alter the behavior of the lzc_promote() function. +At the time of writing, all data passed to it is ignored and callers should pass NULL to ensure that behavior remains the same with future extensions. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp .LP diff --git a/man/man3/lzc_receive.3 b/man/man3/lzc_receive.3 index 14c603660759..d5c923fced3e 100644 --- a/man/man3/lzc_receive.3 +++ b/man/man3/lzc_receive.3 @@ -29,36 +29,29 @@ This manual page is part of the OpenZFS Programmer's Manual. .SH SYNOPSIS #include -\fBint\fR \fBlzc_receive\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t -*\fR\fIprops\fR, \fBconst char *\fR\fIorigin\fR, \fBboolean_t\fR \fIforce\fR, -\fBint\fR \fIfd\fR); +\fBint\fR \fBlzc_receive\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t *\fR\fIprops\fR, \fBconst char *\fR\fIorigin\fR, \fBboolean_t\fR \fIforce\fR, \fBint\fR \fIfd\fR); .SH NAME lzc_receive \- Create a snapshot from a zfs send stream .SH DESCRIPTION .LP -The \fBlzc_receive\fR() function reads a zfs send stream from the file -descriptor \fIfd\fR to atomically create the snapshot \fIsnapname\fR. Any -properties specified by \fIprops\fR shall be set as received properties. +The \fBlzc_receive\fR() function reads a zfs send stream from the file descriptor \fIfd\fR to atomically create the snapshot \fIsnapname\fR. +Any properties specified by \fIprops\fR shall be set as received properties. If the stream is a clone, its origin snapshot must be specified by \fIorigin\fR. -The \fIforce\fR flag will cause the target filesystem to be rolled back or -destroyed if necessary to receive the send stream. +The \fIforce\fR flag will cause the target filesystem to be rolled back or destroyed if necessary to receive the send stream. -This interface does not work on deduplicated streams (those with -DMU_BACKUP_FEATURE_DEDUP) at this time. Also, O_NONBLOCK is not supported on -\fIfd\fR. +This interface does not work on deduplicated streams (those with DMU_BACKUP_FEATURE_DEDUP) at this time. +Also, O_NONBLOCK is not supported on \fIfd\fR. .SH RETURN VALUES .sp .LP Upon successful completion, 0 is returned. .sp -On error, an error is returned from one of the holds where an error occurred -and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific -information when \fIerrlist\fR is non-NULL. The caller must call -\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. +On error, an error is returned from one of the holds where an error occurred and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific information when \fIerrlist\fR is non-NULL. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp @@ -70,9 +63,9 @@ The \fBlzc_receive()\fR function shall fail if: \fB\fBEAGAIN\fR\fR, \fB\fBEWOULDBLOCK\fR\fR .ad .RS 13n -The file descriptor was marked non-blocking and the call would block. This is -from \fBread\fR(2). This indicates a userland programming bug because \fIfd\fB -should never be set as being non-blocking. +The file descriptor was marked non-blocking and the call would block. +This is from \fBread\fR(2). +This indicates a userland programming bug because \fIfd\fB should never be set as being non-blocking. .RE .sp @@ -118,8 +111,8 @@ The pool was uninitialized and a pool with the same GUID already existed. \fB\fBEFAULT\fR\fR .ad .RS 13n -Internal issue occurred when copying command data from userland to kernel. See -Illumos ddi_copyin(9F). +Internal issue occurred when copying command data from userland to kernel. +See Illumos ddi_copyin(9F). .RE .sp @@ -130,7 +123,8 @@ Illumos ddi_copyin(9F). .RS 13n Reading the dmu replay record header from the file descriptor failed. .sp -A low level error occurred. This is from \fBread\fR(2). +A low level error occurred. +This is from \fBread\fR(2). .RE .sp @@ -161,7 +155,8 @@ The \fIorigin\fR is specified, but \fIorigin\fR and \fIsnapname\fR are not both \fB\fBEISDIR\fR\fR .ad .RS 13n -The file descriptor \fIfd\fR belongs to a directory. This is from \fBread\fR(2). +The file descriptor \fIfd\fR belongs to a directory. +This is from \fBread\fR(2). .RE :sp @@ -233,5 +228,4 @@ File descriptors with O_NONBLOCK do not fail immediately. .SH SEE ALSO .sp .LP -\fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), \fBlzc_receive\fR(3), \fBwrite\fR(2), -\fBzfs\fR(8) +\fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), \fBlzc_receive\fR(3), \fBwrite\fR(2), \fBzfs\fR(8) diff --git a/man/man3/lzc_rename.3 b/man/man3/lzc_rename.3 index 6fa2c3f6e32f..1e26a60c8dfc 100644 --- a/man/man3/lzc_rename.3 +++ b/man/man3/lzc_rename.3 @@ -33,15 +33,14 @@ This manual page is part of the OpenZFS Programmer's Manual. \fBint\fR \fBlzc_rename\fR(\fBconst char *\fR\fIoldname\fR, \fBchar *\fR\fInewname\fR, \fBnvlist_t *\fR\fIopts\fR, \fBchar **\fR\fIerrname\fR); .SH NAME -lzc_rename \- Rollback this filesystem or volume to its most recent snapshot. +lzc_rename \- Rollback this filesystem or volume to its most recent snapshot. .SH DESCRIPTION .LP -The \fBlibzfs_rename\fR() function will rename a dataset, volume or snapshot. +The \fBlibzfs_rename\fR() function will rename a dataset, volume or snapshot. -For legacy purposes, it will make an attempt to unmount the dataset, volume or -snapsot before a rename is done. To ensure atomicity, userland should unmount -the dataset, volume or snapshot before calling this. +For legacy purposes, it will make an attempt to unmount the dataset, volume or snapsot before a rename is done. +To ensure atomicity, userland should unmount the dataset, volume or snapshot before calling this. .I oldname shall be the name of the current dataset. @@ -50,23 +49,24 @@ shall be the name of the current dataset. shall be the new name of the dataset. .I opts -shall be an nvlist_t that allows changes to the behavior. The only option -accepted at this time is the boolean "recursive" key. That will rename -snapshots of child datasets. This is intended to complement -\fBlzc_snapshot\fR() when multiple snapshots are made with the same name. +shall be an nvlist_t that allows changes to the behavior. +The only option accepted at this time is the boolean "recursive" key. +That will rename snapshots of child datasets. +This is intended to complement \fBlzc_snapshot\fR() when multiple snapshots are made with the same name. .I errname -shall be a pointer to a string pointer. It can be NULL. It is only used when an -error occurs when renaming snapshots recursively. +shall be a pointer to a string pointer. +It can be NULL. +It is only used when an error occurs when renaming snapshots recursively. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. -If an error occurs on a recursive snapshot rename and \fIerrname\fR is -non-NULL, a strdup()-allocated string wll be returned via \fIerrname\fR. The -caller must free it with \fBstrfree\fR(). +If an error occurs on a recursive snapshot rename and \fIerrname\fR is non-NULL, a strdup()-allocated string wll be returned via \fIerrname\fR. +The caller must free it with \fBstrfree\fR(). .SH ERRORS .sp @@ -100,8 +100,7 @@ The string \fIfsname\fR exceeds 256 characters. .sp The string \fInewname\fR exceeds 256 characters. .sp -The new name of a recursively renamed child snapshot would exceed 256 -characters. +The new name of a recursively renamed child snapshot would exceed 256 characters. .RE .sp diff --git a/man/man3/lzc_rollback.3 b/man/man3/lzc_rollback.3 index cc5e3f744ce6..a326641d8702 100644 --- a/man/man3/lzc_rollback.3 +++ b/man/man3/lzc_rollback.3 @@ -33,7 +33,7 @@ This manual page is part of the OpenZFS Programmer's Manual. \fBint\fR \fBlzc_rollback\fR(\fBconst char *\fR\fIfsname\fR, \fBchar *\fR\fIsnapnamebuf\fR, \fBint\fR \fIsnapnamelen\fR); .SH NAME -lzc_rollback \- Rollback this filesystem or volume to its most recent snapshot. +lzc_rollback \- Rollback this filesystem or volume to its most recent snapshot. .SH DESCRIPTION .LP @@ -43,8 +43,8 @@ The \fBlzc_rollback\fR() function rolls back a live dataset or volume to its mos shall be the name of the most recent snapshot to rollback. .I snapnamebuf -shall be a pointer to a string to fill with the name of the most recent -snapshot. If NULL, it wll be ignored. +shall be a pointer to a string to fill with the name of the most recent snapshot. +If NULL, it wll be ignored. .I snapnamelen shall be the length of \fIsnapnamebuf\fR. @@ -52,8 +52,8 @@ shall be the length of \fIsnapnamebuf\fR. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned and \fIsnapnamebuf\fR is filled if -non-NULL. Otherwise, an error is returned. +Upon successful completion, 0 is returned and \fIsnapnamebuf\fR is filled if non-NULL. +Otherwise, an error is returned. .SH ERRORS .sp diff --git a/man/man3/lzc_send.3 b/man/man3/lzc_send.3 index 0e8cc02bdd67..cee466dcf5e1 100644 --- a/man/man3/lzc_send.3 +++ b/man/man3/lzc_send.3 @@ -29,26 +29,22 @@ This manual page is part of the OpenZFS Programmer's Manual. .SH SYNOPSIS #include -\fBint\fR \fBlzc_send\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char -*\fR\fIfrom\fR, \fBint\fR \fIfd\fR, \fBenum lzc_send_flags\fR \fIflags); +\fBint\fR \fBlzc_send\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char *\fR\fIfrom\fR, \fBint\fR \fIfd\fR, \fBenum lzc_send_flags\fR \fIflags); .SH NAME lzc_send \- Generate a send stream from a snapshot .SH DESCRIPTION .LP -The \fBlzc_send\fR() function writes a ZFS stream to -file descriptor \fIfd\fR from snapshot \fIsnapname\fR of dataset \fIfrom\fR. +The \fBlzc_send\fR() function writes a ZFS stream to file descriptor \fIfd\fR from snapshot \fIsnapname\fR of dataset \fIfrom\fR. .SH RETURN VALUES .sp .LP Upon successful completion, 0 is returned. .sp -On error, an error is returned from one of the holds where an error occurred -and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific -information when \fIerrlist\fR is non-NULL. The caller must call -\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. +On error, an error is returned from one of the holds where an error occurred and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific information when \fIerrlist\fR is non-NULL. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp @@ -60,8 +56,8 @@ The \fBlzc_send()\fR function shall fail if: \fB\fBEAGAIN\fR\fR, \fB\fBEWOULDBLOCK\fR\fR .ad .RS 13n -The file descriptor was marked non-blocking and the call would block. This is -from \fBwrite\fR(2). +The file descriptor was marked non-blocking and the call would block. +This is from \fBwrite\fR(2). .RE .sp @@ -79,8 +75,8 @@ The file descriptor \fIfd\fR is invalid. \fB\fBEDESTADDRREQ\fR\fR .ad .RS 13n -The file descriptor is a datagram socket for which a peer address has not been -set using \fBconnect\fR(2). This is from \fBwrite\fR(2). +The file descriptor is a datagram socket for which a peer address has not been set using \fBconnect\fR(2). +This is from \fBwrite\fR(2). .RE .sp @@ -98,8 +94,8 @@ The pool was uninitialized and a pool with the same GUID already existed. \fB\fBEFAULT\fR\fR .ad .RS 13n -Internal issue occurred when copying command data from userland to kernel. See -Illumos ddi_copyin(9F). +Internal issue occurred when copying command data from userland to kernel. +See Illumos ddi_copyin(9F). .RE .sp @@ -108,9 +104,8 @@ Illumos ddi_copyin(9F). \fB\fBEFBIG\fR\fR .ad .RS 13n -The file descriptor \fIfd\fR is a file and writing to it would cause it to -exceed the maximum file size permitted by the filesystem. This is from -\fBwrite\fR(2). +The file descriptor \fIfd\fR is a file and writing to it would cause it to exceed the maximum file size permitted by the filesystem. +This is from \fBwrite\fR(2). .RE .sp @@ -119,7 +114,8 @@ exceed the maximum file size permitted by the filesystem. This is from \fB\fBEIO\fR\fR .ad .RS 13n -A low level error occurred. This is from \fBwrite\fR(2). +A low level error occurred. +This is from \fBwrite\fR(2). .RE .sp @@ -179,7 +175,8 @@ Failed to allocate memory necessary to send \fIparams\fR to the kernel. \fB\fBENOSPC\fR\fR .ad .RS 13n -The file descriptor \fIfd\fR cannot be appended. This is from \fBwrite\fR(2). +The file descriptor \fIfd\fR cannot be appended. +This is from \fBwrite\fR(2). .RE .sp @@ -188,8 +185,8 @@ The file descriptor \fIfd\fR cannot be appended. This is from \fBwrite\fR(2). \fB\fBEPIPE\fR\fR .ad .RS 13n -The file descriptor is a pipe whose reading end is closed. This is from -\fBwrite\fR(2). +The file descriptor is a pipe whose reading end is closed. +This is from \fBwrite\fR(2). .RE .sp @@ -207,7 +204,8 @@ Permission denied by zone security policy. \fB\fBESRCH\fR\fR .ad .RS 13n -A specified, but valid, bookmark was not found. This merits a bug report. +A specified, but valid, bookmark was not found. +This merits a bug report. .RE .SH BUGS @@ -216,5 +214,4 @@ File descriptors with O_NONBLOCK do not fail immediately. .SH SEE ALSO .sp .LP -\fBconnect\fR(2) \fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), -\fBlzc_receive\fR(3), \fBwrite\fR(2), \fBzfs\fR(8) +\fBconnect\fR(2) \fBlibzfs_core.h\fR(3), \fBlzc_hold\fR(3), \fBlzc_receive\fR(3), \fBwrite\fR(2), \fBzfs\fR(8) diff --git a/man/man3/lzc_send_progress.3 b/man/man3/lzc_send_progress.3 index c59149fd75d7..a310ed4af3f8 100644 --- a/man/man3/lzc_send_progress.3 +++ b/man/man3/lzc_send_progress.3 @@ -37,9 +37,7 @@ lzc_send_progress \- Query bytes written to fd by active send stream .SH DESCRIPTION .LP -The -\fBlzc_send_progress\fR() -function returns how many bytes have been written by send stream to \fIfd\fR. +The \fBlzc_send_progress\fR() function returns how many bytes have been written by send stream to \fIfd\fR. .SH RETURN VALUES .sp @@ -85,11 +83,9 @@ The string \fIsnapname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or -destroyed. +Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. .sp -Internal error where uninitialized pool lacks a GUID in its config that was -read from the cachefile. +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp The snapshot \fIsnapname\fR does not exist. .sp diff --git a/man/man3/lzc_send_space.3 b/man/man3/lzc_send_space.3 index e06700e97c4d..0dbdac0cd663 100644 --- a/man/man3/lzc_send_space.3 +++ b/man/man3/lzc_send_space.3 @@ -33,13 +33,11 @@ This manual page is part of the OpenZFS Programmer's Manual. \fBint\fR \fBlzc_send_space\fR(\fBconst char *\fR\fIsnapname\fR, \fBconst char *\fR\fIfrom\fR, \fBuint64_t *\fR\fIspacep\fR); .SH NAME -lzc_send_space \- Calculates approximately how many bytes would be written by -lzc_send(). +lzc_send_space \- Calculates approximately how many bytes would be written by lzc_send(). .SH DESCRIPTION .LP -The \fBlzc_send_space\fR() function calculates approximately how many bytes -would be written by lzc_send(). +The \fBlzc_send_space\fR() function calculates approximately how many bytes would be written by lzc_send(). If \fIfrom\fR is NULL, the space for a non-incremental stream is calculated. Calculations for deduplicated streams are not supported. @@ -90,11 +88,9 @@ The string \fIfrom\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or -destroyed. +Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. .sp -Internal error where uninitialized pool lacks a GUID in its config that was -read from the cachefile. +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp The snapshot \fIsnapname\fR does not exist. .sp @@ -118,7 +114,8 @@ Permission denied by zone security policy. .RS 13n The snapshot \fIfrom\fR is not an earlier snapshot than the snapshot \fIsnapname\fR. .sp -The snapshot \fIfrom\fR and the snapshot \fIsnapname\fR are not snapshots of the same dataset. Alternatively, they are not of the same pool. +The snapshot \fIfrom\fR and the snapshot \fIsnapname\fR are not snapshots of the same dataset. +Alternatively, they are not of the same pool. .RE .SH SEE ALSO diff --git a/man/man3/lzc_set_props.3 b/man/man3/lzc_set_props.3 index 9a0f4136c151..313520b24c74 100644 --- a/man/man3/lzc_set_props.3 +++ b/man/man3/lzc_set_props.3 @@ -43,16 +43,15 @@ The \fBlzc_set_props\fR() function will set properties on a given dataset or vol is a string containing the name of a dataset or filesystem. .sp .I props -is a nvlist containing the properties to set. See \fBzfs\fR(8) for descriptions -of properties. +is a nvlist containing the properties to set. +See \fBzfs\fR(8) for descriptions of properties. .sp .I opts is a nvlist containing additional options to pass to this command. .sp -The \fIprops\fR parameter is an nvlist of property names -(with no values) that will be returned for each bookmark. The \fIbmarks\fR -parameter is a pointer to a nvlist of the bookmarks. The caller is responsible -for freeing it with \fBnvlist_free\fR(). +The \fIprops\fR parameter is an nvlist of property names (with no values) that will be returned for each bookmark. +The \fIbmarks\fR parameter is a pointer to a nvlist of the bookmarks. +The caller is responsible for freeing it with \fBnvlist_free\fR(). The format of the returned nvlist as follows: .P @@ -63,8 +62,8 @@ The format of the returned nvlist as follows: .br } -The following are valid properties on bookmarks. All of them are uint64 values -in the nvlist: +The following are valid properties on bookmarks. +All of them are uint64 values in the nvlist: .sp .na \fB\fBguid\fR\fR @@ -95,7 +94,8 @@ A boolean property that specifies that the properties being set were received fr tells the kernel to handle failures by setting all properties that do not fail. This is necessary when setting old-style special properties. .sp -There are 9 old-style special properties that cannot be set atomically with the others. They are: +There are 9 old-style special properties that cannot be set atomically with the others. +They are: .sp filesystem_limit .sp @@ -120,7 +120,8 @@ Unsupported properties will be silently ignored. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned and all properties have been set. Otherwise, an error is returned. +Upon successful completion, 0 is returned and all properties have been set. +Otherwise, an error is returned. .SH ERRORS .sp @@ -203,7 +204,8 @@ An old-style special property was specified without "noatomic" in \fBopts\fR. \fB\fBESRCH\fR\fR .ad .RS 13n -A specified, but valid, bookmark was not found. This merits a bug report. +A specified, but valid, bookmark was not found. +This merits a bug report. .RE .SH SEE ALSO diff --git a/man/man3/lzc_snaprange_space.3 b/man/man3/lzc_snaprange_space.3 index 8e9eb295e247..c00c99e49a3a 100644 --- a/man/man3/lzc_snaprange_space.3 +++ b/man/man3/lzc_snaprange_space.3 @@ -37,16 +37,14 @@ lzc_snaprange_space \- Determine how much space is used by a snapshot range. .SH DESCRIPTION .LP -The -\fBlzc_snaprange_space\fR() -function calculates how much space in bytes the differences between -\fIfirstsnap\fR and \fIlastsnap\fR use in the pool. They must be snapshots of -the same dataset. +The \fBlzc_snaprange_space\fR() function calculates how much space in bytes the differences between \fIfirstsnap\fR and \fIlastsnap\fR use in the pool. +They must be snapshots of the same dataset. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .SH ERRORS .sp .LP @@ -92,11 +90,9 @@ The string \fIlastsnap\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or -destroyed. +Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. .sp -Internal error where uninitialized pool lacks a GUID in its config that was -read from the cachefile. +Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp The snapshot \fIfirstsnap\fR does not exist. .sp @@ -122,10 +118,9 @@ Permission denied by zone security policy. .SH BUGS .LP -Early implementations of the API will return \fB\fBENOENT\fR\fR instead of -\fB\fBEXDEV\fR\fR. The same implementations would also segfault in -\fBlzc_snaprange_space()\fR when \fI*usedp\fR was NULL. These issues were -rectified when the man page was written. +Early implementations of the API will return \fB\fBENOENT\fR\fR instead of \fB\fBEXDEV\fR\fR. +The same implementations would also segfault in \fBlzc_snaprange_space()\fR when \fI*usedp\fR was NULL. +These issues were rectified when the man page was written. .SH SEE ALSO .sp diff --git a/man/man3/lzc_snapshot.3 b/man/man3/lzc_snapshot.3 index 3a0ea0665433..a70789a56d5f 100644 --- a/man/man3/lzc_snapshot.3 +++ b/man/man3/lzc_snapshot.3 @@ -30,43 +30,40 @@ This manual page is part of the OpenZFS Programmer's Manual. .SH SYNOPSIS #include -\fBint\fR \fBlzc_snapshot\fR(\fBnvlist_t *\fR\fIsnaps\fR, \fBnvlist_t -*\fR\fIprops\fR, \fBnvlist_t **\fR\fIerrlist\fR); +\fBint\fR \fBlzc_snapshot\fR(\fBnvlist_t *\fR\fIsnaps\fR, \fBnvlist_t *\fR\fIprops\fR, \fBnvlist_t **\fR\fIerrlist\fR); .SH NAME lzc_snapshot \- Creates a snapshot of a dataset or volume .SH DESCRIPTION .LP -The \fBlzc_snapshot\fR() function creates atomic snapshots of all ZFS -datasets and/or volumes named in the \fIsnaps\fR nvlist. +The \fBlzc_snapshot\fR() function creates atomic snapshots of all ZFS datasets and/or volumes named in the \fIsnaps\fR nvlist. .I snaps -shall be a nvlist containing strings that specify the snapshots to create. All snapshot smust be inside the same pool. +shall be a nvlist containing strings that specify the snapshots to create. +All snapshot smust be inside the same pool. .I props -shall either be NULL or contain a nvlist with properties to set on the snapshot -at creation time. Currently only user properties are supported. It shall be of -the format: +shall either be NULL or contain a nvlist with properties to set on the snapshot at creation time. +Currently only user properties are supported. +It shall be of the format: .sp { user:prop_name -> string value } .I errlist -shall contain a handle that shall be used to store a pointer to a library -allocated nvlist when non-NULL and the operation for at least one hold fails. -The names of the holds shall be the keys while the values shall contain the -error codes and be of type int32. Holds that failed to release because they did -not exist shall also have an entry added. It shall not be touched otherwise. +shall contain a handle that shall be used to store a pointer to a library allocated nvlist when non-NULL and the operation for at least one hold fails. +The names of the holds shall be the keys while the values shall contain the error codes and be of type int32. +Holds that failed to release because they did not exist shall also have an entry added. +It shall not be touched otherwise. .SH RETURN VALUES .sp .LP -Upon successful completion, 0 is returned. Otherwise, an error is returned. +Upon successful completion, 0 is returned. +Otherwise, an error is returned. .sp -On error, an error is returned from one of the holds where an error occurred -and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific -information when \fIerrlist\fR is non-NULL. The caller must call -\fBnvlist_free\fR(\fI*errlist\fR) when this occurs. +On error, an error is returned from one of the holds where an error occurred and \fI*errlist\fR is initialized with a pointer to a nvlist with more specific information when \fIerrlist\fR is non-NULL. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp @@ -78,8 +75,7 @@ The \fBlzc_snapshot()\fR function will fail if: \fB\fBE2BIG\fR\fR .ad .RS 13n -The length of a property value is larger than 8191 characters excluding the -NULL termination character. +The length of a property value is larger than 8191 characters excluding the NULL termination character. .RE .sp @@ -138,8 +134,7 @@ A dataset or volume specified in \fIsnaps\fR does not exist. \fB\fBENOMEM\fR\fR .ad .RS 13n -Failed to allocate memory necessary to send \fIsnaps\fR or \fIprops\fR to the -kernel. +Failed to allocate memory necessary to send \fIsnaps\fR or \fIprops\fR to the kernel. .RE .sp diff --git a/module/nvpair/fnvpair.c b/module/nvpair/fnvpair.c index 1f436d627ccd..b73c2c0a95e6 100644 --- a/module/nvpair/fnvpair.c +++ b/module/nvpair/fnvpair.c @@ -84,32 +84,32 @@ fnvlist_pack_enc(nvlist_t *nvl, size_t *sizep, int encoding) /* * Returns allocated buffer of size *sizep. Caller must free the buffer with - * fnvlist_pack_free(). An alias for fnvlist_pacn_native. + * fnvlist_pack_free(). Allocated buffer is native encoded. */ char * -fnvlist_pack(nvlist_t *nvl, size_t *sizep) +fnvlist_pack_native(nvlist_t *nvl, size_t *sizep) { - return fnvlist_pack_native(nvl, sizep); + return fnvlist_pack_enc(nvl, sizep, NV_ENCODE_NATIVE); } /* * Returns allocated buffer of size *sizep. Caller must free the buffer with - * fnvlist_pack_free(). Allocated buffer is native encoded. + * fnvlist_pack_free(). Allocated buffer is XDR encoded. */ char * -fnvlist_pack_native(nvlist_t *nvl, size_t *sizep) +fnvlist_pack_xdr(nvlist_t *nvl, size_t *sizep) { - return fnvlist_pack_enc(nvl, sizep, NV_ENCODE_NATIVE); + return fnvlist_pack_enc(nvl, sizep, NV_ENCODE_XDR); } /* * Returns allocated buffer of size *sizep. Caller must free the buffer with - * fnvlist_pack_free(). Allocated buffer is XDR encoded. + * fnvlist_pack_free(). An alias for fnvlist_pacn_native. */ char * -fnvlist_pack_xdr(nvlist_t *nvl, size_t *sizep) +fnvlist_pack(nvlist_t *nvl, size_t *sizep) { - return fnvlist_pack_enc(nvl, sizep, NV_ENCODE_XDR); + return fnvlist_pack_native(nvl, sizep); } /*ARGSUSED*/ @@ -543,8 +543,10 @@ fnvpair_value_nvlist(nvpair_t *nvp) EXPORT_SYMBOL(fnvlist_alloc); EXPORT_SYMBOL(fnvlist_free); EXPORT_SYMBOL(fnvlist_size); -EXPORT_SYMBOL(fnvlist_pack); +EXPORT_SYMBOL(fnvlist_pack_enc); +EXPORT_SYMBOL(fnvlist_pack_native); EXPORT_SYMBOL(fnvlist_pack_xdr); +EXPORT_SYMBOL(fnvlist_pack); EXPORT_SYMBOL(fnvlist_pack_free); EXPORT_SYMBOL(fnvlist_unpack); EXPORT_SYMBOL(fnvlist_dup); From a4b38087972e17d980ff2b00b81dc7f33f454c04 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 13:25:29 -0400 Subject: [PATCH 33/40] man/lzc_exists: correct enum values for B_{FALSE,TRUE} The man page had the return values swapped. B_FALSE and B_TRUE are defined in lib/libspl/include/sys/types.h as `typedef enum boolean { B_FALSE, B_TRUE } boolean_t;` Signed-off-by: Manuel Mendez --- man/man3/lzc_exists.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/man3/lzc_exists.3 b/man/man3/lzc_exists.3 index 3d3227b91703..1765b36e15db 100644 --- a/man/man3/lzc_exists.3 +++ b/man/man3/lzc_exists.3 @@ -51,9 +51,9 @@ but it does not apply to bookmarks. .LP On success, the \fBlzc_exists\fR() -function returns a 0 (B_TRUE) when +function returns a 1 (B_TRUE) when .I dataset -exists and 1 (B_FALSE) when +exists and 0 (B_FALSE) when .I dataset does not exist. On failure, the function returns an error code. From 558338e149fa4de0eab2021bccdf7380fbddda40 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 16:58:01 -0400 Subject: [PATCH 34/40] man/lzc_list: remove redundant sentence Signed-off-by: Manuel Mendez --- man/man3/lzc_list.3 | 1 - 1 file changed, 1 deletion(-) diff --git a/man/man3/lzc_list.3 b/man/man3/lzc_list.3 index a473d9a72b70..147d74992070 100644 --- a/man/man3/lzc_list.3 +++ b/man/man3/lzc_list.3 @@ -60,7 +60,6 @@ NAME TYPE DESCRIPTION .sp At present, the fd field is the only supported output method and therefore, it is mandatory. If the name field is a bookmark or snapshot, the recurse field is ignored. -If the passed name is that of a bookmark or snapshot, the recurse field is ignored. If all children are desired, recurse should be set to be a boolean type. If a recursion limit is desired, recurses hould be a uint64_t. If no type is specified, a default behavior consistent with the zfs list command is provided. Valid children of the type nvlist are: From 49e35661441c6cf0b6c5b6ac0b1601e6b7b5766c Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Tue, 27 Oct 2015 17:16:32 -0400 Subject: [PATCH 35/40] man/lzc_get_holds: fix unclosed italic Signed-off-by: Manuel Mendez --- man/man3/lzc_get_holds.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man3/lzc_get_holds.3 b/man/man3/lzc_get_holds.3 index f195be6b9252..3248756c11f5 100644 --- a/man/man3/lzc_get_holds.3 +++ b/man/man3/lzc_get_holds.3 @@ -42,7 +42,7 @@ The nvlist keys will be the short names of the holds while the nvlist values wil The numbers are internal identifiers that have no application to userland in the current iteration of the libzfs_core API. .SH RETURN VALUE -On success, the \fBlzc_get_holds\fR() function returns 0 and fills in \fI*holdsp\fR when \fIholdsp\R is non-NULL. +On success, the \fBlzc_get_holds\fR() function returns 0 and fills in \fI*holdsp\fR when \fIholdsp\fR is non-NULL. On failure, the function returns an error code. .SH ERRORS From 077e165da2ebedb3b82419c42e36c8cf1d2a6118 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Wed, 28 Oct 2015 17:50:44 -0400 Subject: [PATCH 36/40] man: spelling and grammar fixes Signed-off-by: Manuel Mendez --- man/man3/libzfs_core_init.3 | 4 ++-- man/man3/lzc_bookmark.3 | 2 +- man/man3/lzc_clone.3 | 2 +- man/man3/lzc_create.3 | 4 ++-- man/man3/lzc_destroy_bookmarks.3 | 4 ++-- man/man3/lzc_destroy_one.3 | 4 ++-- man/man3/lzc_destroy_snaps.3 | 8 ++++---- man/man3/lzc_get_bookmarks.3 | 4 ++-- man/man3/lzc_get_holds.3 | 4 ++-- man/man3/lzc_hold.3 | 6 +++--- man/man3/lzc_inherit.3 | 2 +- man/man3/lzc_list.3 | 6 +++--- man/man3/lzc_promote.3 | 2 +- man/man3/lzc_receive.3 | 2 +- man/man3/lzc_rename.3 | 6 +++--- man/man3/lzc_rollback.3 | 6 +++--- man/man3/lzc_send.3 | 2 +- man/man3/lzc_send_progress.3 | 4 ++-- man/man3/lzc_send_space.3 | 2 +- man/man3/lzc_set_props.3 | 2 +- man/man3/lzc_snaprange_space.3 | 2 +- man/man3/lzc_snapshot.3 | 4 ++-- 22 files changed, 41 insertions(+), 41 deletions(-) diff --git a/man/man3/libzfs_core_init.3 b/man/man3/libzfs_core_init.3 index e9c6dd237b82..001b6191d060 100644 --- a/man/man3/libzfs_core_init.3 +++ b/man/man3/libzfs_core_init.3 @@ -40,7 +40,7 @@ libzfs_core_init, libzfs_core_fini \- Initialize and deinitialize libzfs_core li .LP The \fBlibzfs_core_init\fR() function is a singleton constructor for the libzfs_core library. It should be called once at program initialization. -Multiple calls to \fBlibzfs_core_init\fR() are fine provided that they be matched by an equal number of alls to the \fBlibzfs_core_fini\fR() function. +Multiple calls to \fBlibzfs_core_init\fR() are fine provided that they be matched by an equal number of calls to the \fBlibzfs_core_fini\fR() function. .SH RETURN VALUES .sp @@ -59,4 +59,4 @@ In this situation, the error code from \fBopen\fR(2) will be returned. .SH "SEE ALSO" .sp .LP -"\fIlibzfs_core.h\fR(3)", "\fIopen\fR(2)" +\fIlibzfs_core.h\fR(3), \fIopen\fR(2) diff --git a/man/man3/lzc_bookmark.3 b/man/man3/lzc_bookmark.3 index 428ce0bead9d..931a706bdc4f 100644 --- a/man/man3/lzc_bookmark.3 +++ b/man/man3/lzc_bookmark.3 @@ -105,7 +105,7 @@ A snapshot name in the \fIbookmarks\fR nvlist exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_clone.3 b/man/man3/lzc_clone.3 index c28d3246f4a7..14ca1bf78477 100644 --- a/man/man3/lzc_clone.3 +++ b/man/man3/lzc_clone.3 @@ -109,7 +109,7 @@ The snapshot name \fIorigin\fR nvlist exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp The dataset \fIfsname\fR does not exist. .RE diff --git a/man/man3/lzc_create.3 b/man/man3/lzc_create.3 index 7bedb16d4bf0..d7e63cef87e8 100644 --- a/man/man3/lzc_create.3 +++ b/man/man3/lzc_create.3 @@ -89,7 +89,7 @@ The dataset name \fIfsname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp @@ -113,7 +113,7 @@ Failed to allocate memory necessary to send \fIprops\fR to the kernel. .RS 13n The requested ZPL version is not supported. .sp -A feature has been requested (e.g. normalization) that hte requested ZPL version doe sont support. +A feature has been requested (e.g. normalization) that the requested ZPL version does not support. .RE .sp diff --git a/man/man3/lzc_destroy_bookmarks.3 b/man/man3/lzc_destroy_bookmarks.3 index 7f7cc165a8a9..b1e8ab18c4a2 100644 --- a/man/man3/lzc_destroy_bookmarks.3 +++ b/man/man3/lzc_destroy_bookmarks.3 @@ -71,7 +71,7 @@ The pool was uninitialized and a pool with the same GUID already existed. \fB\fBEINVAL\fR\fR .ad .RS 13n -Invalid boomark name specified in \fIbmarks\fR. +Invalid bookmark name specified in \fIbmarks\fR. .RE .sp @@ -91,7 +91,7 @@ Bookmark name specified in \fIbmarks\fR is too long. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .RE diff --git a/man/man3/lzc_destroy_one.3 b/man/man3/lzc_destroy_one.3 index 79f6bbd813b6..a7bdb783ae63 100644 --- a/man/man3/lzc_destroy_one.3 +++ b/man/man3/lzc_destroy_one.3 @@ -75,7 +75,7 @@ Dataset named \fIdataset\fR has a long hold from a zfs send stream or a user hol .RS 13n The pool was uninitialized and a pool with the same GUID already existed. .sp -The dataset or volume \fIfsname\fR has children in its pool's namespace. +The dataset or volume \fIfsname\fR has children in it's pool's namespace. .RE .sp @@ -106,7 +106,7 @@ The string \fIfsname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_destroy_snaps.3 b/man/man3/lzc_destroy_snaps.3 index 83b23514c5c9..51c9c07d2458 100644 --- a/man/man3/lzc_destroy_snaps.3 +++ b/man/man3/lzc_destroy_snaps.3 @@ -50,7 +50,7 @@ If \fIdefer\fR is set, and a snapshot has user holds or clones, it will be marke .sp .LP Upon successful completion, 0 is returned. -This means that all snapshots were destroyed (excluding those that did not exist) or were marked for later distruction if \fIdefer\fR is set. +This means that all snapshots were destroyed (excluding those that did not exist) or were marked for later destruction if \fIdefer\fR is set. .sp On error, an error is returned from one of the snapshots where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. @@ -69,7 +69,7 @@ Snapshot held by a user hold and \fIdefer\fR is not specified. .sp Snapshot held by a zfs send stream and \fIdefer\fR is not specified. .sp -Snapshot held by an open file hanle or program's present working directory and \fIdefer\fR is not specified. +Snapshot held by an open file handle or program's present working directory and \fIdefer\fR is not specified. .RE .sp @@ -89,7 +89,7 @@ This snapshot is the parent of clones and cannot be deleted. \fB\fBEINVAL\fR\fR .ad .RS 13n -No snaphsots specified in \fIsnaps\fR. +No snapshots specified in \fIsnaps\fR. .sp The nvlist \fIsnaps\fR is not a valid nvlist. .RE @@ -111,7 +111,7 @@ Snapshot name specified in \fIsnaps\fR is too long. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_get_bookmarks.3 b/man/man3/lzc_get_bookmarks.3 index 12d7419e99f9..16c400652c71 100644 --- a/man/man3/lzc_get_bookmarks.3 +++ b/man/man3/lzc_get_bookmarks.3 @@ -22,7 +22,7 @@ .\" .\" Copyright 2015 ClusterHQ Inc. All rights reserved. .\" -.TH lzc_get_boomarks 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" +.TH lzc_get_bookmarks 3 "2015 JUL 7" "OpenZFS" "OpenZFS Programmer's Manual" .SH PROLOG This manual page is part of the OpenZFS Programmer's Manual. @@ -125,7 +125,7 @@ The dataset name \fIfsname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_get_holds.3 b/man/man3/lzc_get_holds.3 index 3248756c11f5..75cd6dceff54 100644 --- a/man/man3/lzc_get_holds.3 +++ b/man/man3/lzc_get_holds.3 @@ -51,7 +51,7 @@ can fail with the following errors: .TP .B ENOENT -Pool does not exist, or if unintialized, the cachefile is out of sync because loading the pool failed due to an exported or destroyed pool. +Pool does not exist, or if uninitialized, the cachefile is out of sync because loading the pool failed due to an exported or destroyed pool. If pool exists, snapshot does not exist. .TP .B EEXIST @@ -102,7 +102,7 @@ The string \fIsnapname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_hold.3 b/man/man3/lzc_hold.3 index 0de01934f10f..9cc8a40bf210 100644 --- a/man/man3/lzc_hold.3 +++ b/man/man3/lzc_hold.3 @@ -50,11 +50,11 @@ Snapshots preserved in the way shall be destroyed as the user hold is removed. If the snapshot has been marked for deferred destroy by calling \fBlzc_destroy_snaps\fR() with defer=B_TRUE, it does not have any clones, and all the user holds are removed, then the snapshot shall be destroyed. .I snaps -shall be a nvlist with zfs snapshots to hold to hold. +shall be a nvlist with zfs snapshots to hold. It shall store string keys that are the snapshots and values that are the hold names. .I cleanup_fd -shall be a file descriptor that specifies thta the hold is temporary and is to be closed when the specified file descriptor is closed. +shall be a file descriptor that specifies the hold is temporary and is to be closed when the specified file descriptor is closed. Specifying the file descriptor 0 disables this behavior while specifying the file descriptor -1 shall make the hold close when the file descriptor for /dev/zfs held by the library is closed. .I errlist @@ -130,7 +130,7 @@ A snapshot or hold name specified in \fIsnaps\fR nvlist exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_inherit.3 b/man/man3/lzc_inherit.3 index 1a5ef3468acd..ab9479dbc49b 100644 --- a/man/man3/lzc_inherit.3 +++ b/man/man3/lzc_inherit.3 @@ -94,7 +94,7 @@ Failed to allocate memory necessary to send \fIopts\fR to the kernel. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_list.3 b/man/man3/lzc_list.3 index 147d74992070..0b649cb49d67 100644 --- a/man/man3/lzc_list.3 +++ b/man/man3/lzc_list.3 @@ -61,7 +61,7 @@ NAME TYPE DESCRIPTION At present, the fd field is the only supported output method and therefore, it is mandatory. If the name field is a bookmark or snapshot, the recurse field is ignored. If all children are desired, recurse should be set to be a boolean type. -If a recursion limit is desired, recurses hould be a uint64_t. +If a recursion limit is desired, recurses should be a uint64_t. If no type is specified, a default behavior consistent with the zfs list command is provided. Valid children of the type nvlist are: .sp .in +2 @@ -77,7 +77,7 @@ NAME TYPE DESCRIPTION .in -2 .sp Whenever a boolean type is specified, any type may be passed and be considered boolean. -However, future extensions may accept alternate types and consequently, backward compatibility is only guarenteed to callers passing a boolean type that contains no value. +However, future extensions may accept alternate types and consequently, backward compatibility is only guaranteed to callers passing a boolean type that contains no value. A boolean that contains B_TRUE or B_FALSE is considered a separate type from a boolean that contains no value. Additionally, future enhancements to zfs may create a new type and callers that only wish to handle existing types should specify them explicitly rather than relying on the default behavior. .sp @@ -286,7 +286,7 @@ The string \fIname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_promote.3 b/man/man3/lzc_promote.3 index bde99d39551d..99b02550421e 100644 --- a/man/man3/lzc_promote.3 +++ b/man/man3/lzc_promote.3 @@ -103,7 +103,7 @@ Failed to allocate memory necessary to send \fIopts\fR to the kernel. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_receive.3 b/man/man3/lzc_receive.3 index d5c923fced3e..d10950745520 100644 --- a/man/man3/lzc_receive.3 +++ b/man/man3/lzc_receive.3 @@ -176,7 +176,7 @@ The string \fIsnapname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_rename.3 b/man/man3/lzc_rename.3 index 1e26a60c8dfc..7a88cce04d49 100644 --- a/man/man3/lzc_rename.3 +++ b/man/man3/lzc_rename.3 @@ -39,7 +39,7 @@ lzc_rename \- Rollback this filesystem or volume to its most recent snapshot. .LP The \fBlibzfs_rename\fR() function will rename a dataset, volume or snapshot. -For legacy purposes, it will make an attempt to unmount the dataset, volume or snapsot before a rename is done. +For legacy purposes, it will make an attempt to unmount the dataset, volume or snapshot before a rename is done. To ensure atomicity, userland should unmount the dataset, volume or snapshot before calling this. .I oldname @@ -65,7 +65,7 @@ It is only used when an error occurs when renaming snapshots recursively. Upon successful completion, 0 is returned. Otherwise, an error is returned. -If an error occurs on a recursive snapshot rename and \fIerrname\fR is non-NULL, a strdup()-allocated string wll be returned via \fIerrname\fR. +If an error occurs on a recursive snapshot rename and \fIerrname\fR is non-NULL, a strdup()-allocated string will be returned via \fIerrname\fR. The caller must free it with \fBstrfree\fR(). .SH ERRORS @@ -111,7 +111,7 @@ The new name of a recursively renamed child snapshot would exceed 256 characters .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .RE diff --git a/man/man3/lzc_rollback.3 b/man/man3/lzc_rollback.3 index a326641d8702..e605143fe81b 100644 --- a/man/man3/lzc_rollback.3 +++ b/man/man3/lzc_rollback.3 @@ -44,7 +44,7 @@ shall be the name of the most recent snapshot to rollback. .I snapnamebuf shall be a pointer to a string to fill with the name of the most recent snapshot. -If NULL, it wll be ignored. +If NULL, it will be ignored. .I snapnamelen shall be the length of \fIsnapnamebuf\fR. @@ -74,7 +74,7 @@ The dataset has a hold. \fB\fBEDQUOT\fR\fR .ad .RS 13n -The snapshot uses more data than th file system quota. +The snapshot uses more data than the file system quota. .RE .sp @@ -112,7 +112,7 @@ The string \fIfsname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_send.3 b/man/man3/lzc_send.3 index cee466dcf5e1..789c07e2a4b0 100644 --- a/man/man3/lzc_send.3 +++ b/man/man3/lzc_send.3 @@ -153,7 +153,7 @@ The string \fIsnapname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_send_progress.3 b/man/man3/lzc_send_progress.3 index a310ed4af3f8..564b5787243a 100644 --- a/man/man3/lzc_send_progress.3 +++ b/man/man3/lzc_send_progress.3 @@ -83,13 +83,13 @@ The string \fIsnapname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp The snapshot \fIsnapname\fR does not exist. .sp -No active send stream was found that maches \fIfd\fR and \fIsnapname\fR +No active send stream was found that matches \fIfd\fR and \fIsnapname\fR .RE .sp diff --git a/man/man3/lzc_send_space.3 b/man/man3/lzc_send_space.3 index 0dbdac0cd663..c5d5ed1acf71 100644 --- a/man/man3/lzc_send_space.3 +++ b/man/man3/lzc_send_space.3 @@ -88,7 +88,7 @@ The string \fIfrom\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_set_props.3 b/man/man3/lzc_set_props.3 index 313520b24c74..f51fe3653873 100644 --- a/man/man3/lzc_set_props.3 +++ b/man/man3/lzc_set_props.3 @@ -164,7 +164,7 @@ The dataset name \fIfsname\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_snaprange_space.3 b/man/man3/lzc_snaprange_space.3 index c00c99e49a3a..4b5e39ce5fb4 100644 --- a/man/man3/lzc_snaprange_space.3 +++ b/man/man3/lzc_snaprange_space.3 @@ -90,7 +90,7 @@ The string \fIlastsnap\fR exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loadng unitialized pool from cachefile failed because the pool was exported or destroyed. +Loadng uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp diff --git a/man/man3/lzc_snapshot.3 b/man/man3/lzc_snapshot.3 index a70789a56d5f..d2d8643083c8 100644 --- a/man/man3/lzc_snapshot.3 +++ b/man/man3/lzc_snapshot.3 @@ -41,7 +41,7 @@ The \fBlzc_snapshot\fR() function creates atomic snapshots of all ZFS datasets a .I snaps shall be a nvlist containing strings that specify the snapshots to create. -All snapshot smust be inside the same pool. +All snapshots must be inside the same pool. .I props shall either be NULL or contain a nvlist with properties to set on the snapshot at creation time. @@ -121,7 +121,7 @@ A property name in \fIprops\fR nvlist exceeds 256 characters. .RS 13n Pool does not exist. .sp -Loading unitialized pool from cachefile failed because the pool was exported or destroyed. +Loading uninitialized pool from cachefile failed because the pool was exported or destroyed. .sp Internal error where uninitialized pool lacks a GUID in its config that was read from the cachefile. .sp From 5525632cc39e15ce1e31a4ade9a2ac17839a245f Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Thu, 29 Oct 2015 13:36:55 -0400 Subject: [PATCH 37/40] man: some formatting fixes Signed-off-by: Manuel Mendez --- man/man3/libzfs_core.h.3 | 2 +- man/man3/lzc_clone.3 | 6 +++--- man/man3/lzc_receive.3 | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/man/man3/libzfs_core.h.3 b/man/man3/libzfs_core.h.3 index 8ba1f0fe93d7..d4916844d6b4 100644 --- a/man/man3/libzfs_core.h.3 +++ b/man/man3/libzfs_core.h.3 @@ -80,7 +80,7 @@ header shall define the following function prototype headers: .p \fBint\fR \fBlzc_get_holds\fR(\fBconst char *\fR\fIsnapname\fR, \fBnvlist_t **\fR\fIholdsp\fR); .sp -\fBint\fR \fBlzc_inherit\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR fIpropname\fR, \fBnvlist_t *\fR\fIopts\fR); +\fBint\fR \fBlzc_inherit\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR\fIpropname\fR, \fBnvlist_t *\fR\fIopts\fR); .p \fBint\fR \fBlzc_rename\fR(\fBconst char *\fR\fIoldname\fR, \fBchar *\fR\fInewname\fR, \fBnvlist_t *\fR\fIopts\fR, \fBchar **\fR\fIerrname\fR); .sp diff --git a/man/man3/lzc_clone.3 b/man/man3/lzc_clone.3 index 14ca1bf78477..4914754c5086 100644 --- a/man/man3/lzc_clone.3 +++ b/man/man3/lzc_clone.3 @@ -30,7 +30,7 @@ This manual page is part of the OpenZFS Programmer's Manual. .SH SYNOPSIS #include -\fBint\fR \fBlzc_clone\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR \fIorigin\fR, \fBnvlist_t *\fR\fIprops\fR); +\fBint\fR \fBlzc_clone\fR(\fBconst char *\fR\fIfsname\fR, \fBconst char *\fR\fIorigin\fR, \fBnvlist_t *\fR\fIprops\fR); .SH NAME lzc_clone \- Creates a clone from a snapshot @@ -42,9 +42,9 @@ The function creates a ZFS dataset or volume named .I fsname from the snapshot -.fs origin . +.I origin\fR. Properties may optionally be set using -.I props . +.I props\fR. .SH RETURN VALUES .sp diff --git a/man/man3/lzc_receive.3 b/man/man3/lzc_receive.3 index d10950745520..e0705ae6df8a 100644 --- a/man/man3/lzc_receive.3 +++ b/man/man3/lzc_receive.3 @@ -65,7 +65,7 @@ The \fBlzc_receive()\fR function shall fail if: .RS 13n The file descriptor was marked non-blocking and the call would block. This is from \fBread\fR(2). -This indicates a userland programming bug because \fIfd\fB should never be set as being non-blocking. +\fBThis indicates a userland programming bug\fR because \fIfd\fR should never be set as being non-blocking. .RE .sp @@ -159,7 +159,7 @@ The file descriptor \fIfd\fR belongs to a directory. This is from \fBread\fR(2). .RE -:sp +.sp .ne 2 .na \fB\fBENAMETOOLONG\fR\fR @@ -218,7 +218,7 @@ Permission denied by zone security policy. \fB\fBETXTBSY\fR\fR .ad .RS 13n -The force flag has not been set, but the dataset belonging to \fRsnapname\fI has been modified. +The force flag has not been set, but the dataset belonging to \fIsnapname\fR has been modified. .RE From 3dda865ae3efd57d9e60f02da0bb9a667e742d68 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Thu, 29 Oct 2015 13:49:41 -0400 Subject: [PATCH 38/40] man: fix some function names/args Signed-off-by: Manuel Mendez --- man/man3/lzc_bookmark.3 | 2 +- man/man3/lzc_clone.3 | 4 +--- man/man3/lzc_create.3 | 4 ++-- man/man3/lzc_rename.3 | 2 +- man/man3/lzc_snaprange_space.3 | 2 ++ 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/man/man3/lzc_bookmark.3 b/man/man3/lzc_bookmark.3 index 931a706bdc4f..d4ffadeb2e61 100644 --- a/man/man3/lzc_bookmark.3 +++ b/man/man3/lzc_bookmark.3 @@ -37,7 +37,7 @@ lzc_bookmark \- Creates bookmarks from snapshot .SH DESCRIPTION .LP -The \fBlibzfs_snapshot\fR() function creates atomic snapshots of all ZFS datasets and/or volumes named in the \fIsnaps\fR nvlist. +The \fBlzc_bookmark\fR() function creates atomic bookmarks of all ZFS datasets and/or volumes named in the \fIbookmarks\fR nvlist. .I bookmarks shall be a nvlist containing strings whose keys are bookmark names and values are snapshot names to specify which bookmarks to create. diff --git a/man/man3/lzc_clone.3 b/man/man3/lzc_clone.3 index 4914754c5086..e8d7c3fb78ce 100644 --- a/man/man3/lzc_clone.3 +++ b/man/man3/lzc_clone.3 @@ -37,9 +37,7 @@ lzc_clone \- Creates a clone from a snapshot .SH DESCRIPTION .LP -The -\fBlibzfs_clone\fR() -function creates a ZFS dataset or volume named +The \fBlzc_clone\fR() function creates a ZFS dataset or volume named .I fsname from the snapshot .I origin\fR. diff --git a/man/man3/lzc_create.3 b/man/man3/lzc_create.3 index d7e63cef87e8..340b294f8c51 100644 --- a/man/man3/lzc_create.3 +++ b/man/man3/lzc_create.3 @@ -37,7 +37,7 @@ lzc_create \- Create a ZFS dataset or volume .SH DESCRIPTION .LP -The \fBlibzfs_create\fR() function creates a dataset or zvol according to \fItype\fR. +The \fBlzc_create\fR() function creates a dataset or zvol according to \fItype\fR. Optional properties are passed through \fIprops\fR. .SH RETURN VALUES @@ -49,7 +49,7 @@ Otherwise, an error is returned. .SH ERRORS .sp .LP -The \fBlzc_inherit()\fR function will fail if: +The \fBlzc_create()\fR function will fail if: .sp .ne 2 .na diff --git a/man/man3/lzc_rename.3 b/man/man3/lzc_rename.3 index 7a88cce04d49..1b5f114c7ec9 100644 --- a/man/man3/lzc_rename.3 +++ b/man/man3/lzc_rename.3 @@ -96,7 +96,7 @@ The pool was uninitialized and a pool with the same GUID already existed. \fB\fBENAMETOOLONG\fR\fR .ad .RS 13n -The string \fIfsname\fR exceeds 256 characters. +The string \fIoldname\fR exceeds 256 characters. .sp The string \fInewname\fR exceeds 256 characters. .sp diff --git a/man/man3/lzc_snaprange_space.3 b/man/man3/lzc_snaprange_space.3 index 4b5e39ce5fb4..86f9b7e2fcee 100644 --- a/man/man3/lzc_snaprange_space.3 +++ b/man/man3/lzc_snaprange_space.3 @@ -39,6 +39,8 @@ lzc_snaprange_space \- Determine how much space is used by a snapshot range. .LP The \fBlzc_snaprange_space\fR() function calculates how much space in bytes the differences between \fIfirstsnap\fR and \fIlastsnap\fR use in the pool. They must be snapshots of the same dataset. +.sp +The used space calculated is stored in \fI*usedp\fR. .SH RETURN VALUES .sp From faa443de013b2835a0c9aecad8663884c19f969a Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Thu, 29 Oct 2015 13:50:30 -0400 Subject: [PATCH 39/40] man: text normalization Signed-off-by: Manuel Mendez --- man/man3/lzc_clone.3 | 2 +- man/man3/lzc_destroy_bookmarks.3 | 2 +- man/man3/lzc_destroy_one.3 | 2 +- man/man3/lzc_destroy_snaps.3 | 2 +- man/man3/lzc_exists.3 | 18 +++--------------- man/man3/lzc_get_bookmarks.3 | 2 +- man/man3/lzc_set_props.3 | 2 +- 7 files changed, 9 insertions(+), 21 deletions(-) diff --git a/man/man3/lzc_clone.3 b/man/man3/lzc_clone.3 index e8d7c3fb78ce..83cd05d13ab4 100644 --- a/man/man3/lzc_clone.3 +++ b/man/man3/lzc_clone.3 @@ -96,7 +96,7 @@ The nvlist_t \fIprops\fR could not be understood by the kernel as being NULL or .RS 13n The dataset name \fIfsname\fR exceeds 256 characters. .sp -The snapshot name \fIorigin\fR nvlist exceeds 256 characters. +The snapshot name \fIorigin\fR exceeds 256 characters. .RE .sp diff --git a/man/man3/lzc_destroy_bookmarks.3 b/man/man3/lzc_destroy_bookmarks.3 index b1e8ab18c4a2..95a2d2c03d6d 100644 --- a/man/man3/lzc_destroy_bookmarks.3 +++ b/man/man3/lzc_destroy_bookmarks.3 @@ -51,7 +51,7 @@ Upon successful completion, 0 is returned. .sp On error, an error is returned from one of the bookmarks where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. -The caller must call \fBnvlist_free\fR() on \fIerrlist\fR if this occurs. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp .LP diff --git a/man/man3/lzc_destroy_one.3 b/man/man3/lzc_destroy_one.3 index a7bdb783ae63..8ebf5f730820 100644 --- a/man/man3/lzc_destroy_one.3 +++ b/man/man3/lzc_destroy_one.3 @@ -53,7 +53,7 @@ Upon successful completion, 0 is returned. .sp On error, an error is returned from one of the bookmarks where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. -The caller must call \fBnvlist_free\fR() on \fIerrlist\fR if this occurs. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp .LP diff --git a/man/man3/lzc_destroy_snaps.3 b/man/man3/lzc_destroy_snaps.3 index 51c9c07d2458..bca4fc7a7296 100644 --- a/man/man3/lzc_destroy_snaps.3 +++ b/man/man3/lzc_destroy_snaps.3 @@ -54,7 +54,7 @@ This means that all snapshots were destroyed (excluding those that did not exist .sp On error, an error is returned from one of the snapshots where an error occurred and \fIerrlist\fR is populated with more specific information if a pointer is provided. \fIerrlist\fR shall contain keys with the snapshot names and int32 values of the error codes. -The caller must call \fBnvlist_free\fR() on \fIerrlist\fR if this occurs. +The caller must call \fBnvlist_free\fR(\fI*errlist\fR) when this occurs. .SH ERRORS .sp .LP diff --git a/man/man3/lzc_exists.3 b/man/man3/lzc_exists.3 index 1765b36e15db..ce6af5604ae8 100644 --- a/man/man3/lzc_exists.3 +++ b/man/man3/lzc_exists.3 @@ -37,25 +37,13 @@ lzc_exists \- Test for dataset existence. .SH DESCRIPTION .LP -The -\fBlzc_exists\fR() -function tests whether -.I dataset -exists. -It is more efficient than calling -\fBlzc_list\fR(), -but it does not apply to bookmarks. +The \fBlzc_exists\fR() function tests whether \fIdataset\fR exists. +It is more efficient than calling \fBlzc_list\fR(), but it does not apply to bookmarks. .SH RETURN VALUES .sp .LP -On success, the -\fBlzc_exists\fR() -function returns a 1 (B_TRUE) when -.I dataset -exists and 0 (B_FALSE) when -.I dataset -does not exist. +On success, the \fBlzc_exists\fR() function returns a 1 (B_TRUE) when \fIdataset\fR exists and 0 (B_FALSE) when \fIdataset\fR does not exist. On failure, the function returns an error code. .SH ERRORS diff --git a/man/man3/lzc_get_bookmarks.3 b/man/man3/lzc_get_bookmarks.3 index 16c400652c71..c36d96f56784 100644 --- a/man/man3/lzc_get_bookmarks.3 +++ b/man/man3/lzc_get_bookmarks.3 @@ -41,7 +41,7 @@ lzc_get_bookmarks \- Retrieve bookmarks of a given filesystem The \fBlzc_get_bookmarks\fR() function will retrieve the list of bookmarks for the given file system. The \fIprops\fR parameter is an nvlist of property names (with no values) that will be returned for each bookmark. The \fIbmarks\fR parameter is a pointer to a nvlist of the bookmarks. -The caller is responsible for freeing it with \fBnvlist_free\fR(). +The caller is responsible for freeing it with \fBnvlist_free\fR(\fI*bmarks\fR). The format of the returned nvlist as follows: .P diff --git a/man/man3/lzc_set_props.3 b/man/man3/lzc_set_props.3 index f51fe3653873..99af69659064 100644 --- a/man/man3/lzc_set_props.3 +++ b/man/man3/lzc_set_props.3 @@ -51,7 +51,7 @@ is a nvlist containing additional options to pass to this command. .sp The \fIprops\fR parameter is an nvlist of property names (with no values) that will be returned for each bookmark. The \fIbmarks\fR parameter is a pointer to a nvlist of the bookmarks. -The caller is responsible for freeing it with \fBnvlist_free\fR(). +The caller is responsible for freeing it with \fBnvlist_free\fR(\fI*bmarks\fR). The format of the returned nvlist as follows: .P From 14e490fad6bba66c99ff6f8d99181e262505d9fc Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Thu, 29 Oct 2015 13:52:48 -0400 Subject: [PATCH 40/40] man: rework only first-person sentence Signed-off-by: Manuel Mendez --- man/man3/lzc_destroy_one.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man3/lzc_destroy_one.3 b/man/man3/lzc_destroy_one.3 index 8ebf5f730820..9191fbb7bc0a 100644 --- a/man/man3/lzc_destroy_one.3 +++ b/man/man3/lzc_destroy_one.3 @@ -42,7 +42,7 @@ Destroying snapshots and bookmarks is not currently supported. Call lzc_destroy_snaps and lzc_destroy_bookmarks for those respectively. The only currently valid property is the boolean "defer". -It makes destruction asynchronous such that the only error code back is if we try to destroy something that does not exist. +It makes destruction asynchronous such that the only error code returned is when attempting to destroy something that does not exist. The caller must unmount the dataset before calling this. Otherwise, it will fail.