diff options
author | Keith M Wesolowski <wesolows@foobazco.org> | 2013-12-12 21:44:02 +0000 |
---|---|---|
committer | Keith M Wesolowski <wesolows@foobazco.org> | 2013-12-12 21:44:02 +0000 |
commit | e2f9756b8e9461119d4c8b16701e32425283b31a (patch) | |
tree | 589339198ca8b38dd8280d8664e06d72bca3d83a /usr/src/lib | |
parent | d2ea917c8c4786e6dce9d0fd7f18c55c9f72f16e (diff) | |
parent | 8b36997aa24d9817807faa4efa301ac9c07a2b78 (diff) | |
download | illumos-joyent-release-20131212.tar.gz |
[illumos-gate merge]20131212release-20131212
commit 8b36997aa24d9817807faa4efa301ac9c07a2b78
4391 panic system rather than corrupting pool if we hit bug 4390
commit 78f171005391b928aaf1642b3206c534ed644332
4369 implement zfs bookmarks
4368 zfs send filesystems from readonly pools
commit 973c78e94bf9634782164382c9e291bf81161fa5
4121 vdev_label_init should treat request as succeeded when pool is read only
Conflicts:
usr/src/man/man1m/zfs.1m
usr/src/lib/libzfs/common/mapfile-vers
usr/src/lib/libzfs/common/libzfs_impl.h
usr/src/cmd/zfs/zfs_main.c
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 6 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_dataset.c | 146 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_impl.h | 4 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_iter.c | 62 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_sendrecv.c | 56 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/mapfile-vers | 6 | ||||
-rw-r--r-- | usr/src/lib/libzfs_core/common/libzfs_core.c | 114 | ||||
-rw-r--r-- | usr/src/lib/libzfs_core/common/libzfs_core.h | 32 | ||||
-rw-r--r-- | usr/src/lib/libzfs_core/common/mapfile-vers | 3 | ||||
-rw-r--r-- | usr/src/lib/pyzfs/common/allow.py | 2 |
10 files changed, 370 insertions, 61 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 35d2c26a9b..62dce8f2d4 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. @@ -192,6 +192,7 @@ extern int zpool_log_history(libzfs_handle_t *, const char *); extern int libzfs_errno(libzfs_handle_t *); extern const char *libzfs_error_action(libzfs_handle_t *); extern const char *libzfs_error_description(libzfs_handle_t *); +extern int zfs_standard_error(libzfs_handle_t *, int, const char *); extern void libzfs_mnttab_init(libzfs_handle_t *); extern void libzfs_mnttab_fini(libzfs_handle_t *); extern void libzfs_mnttab_cache(libzfs_handle_t *, boolean_t); @@ -534,6 +535,7 @@ extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *); +extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *); typedef struct get_all_cb { zfs_handle_t **cb_handles; @@ -595,6 +597,7 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *); extern int zfs_send(zfs_handle_t *, const char *, const char *, sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **); +extern int zfs_send_one(zfs_handle_t *, const char *, int); extern int zfs_promote(zfs_handle_t *); extern int zfs_hold(zfs_handle_t *, const char *, const char *, @@ -664,6 +667,7 @@ extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t); extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *, zfs_type_t); extern int zfs_spa_version(zfs_handle_t *, int *); +extern boolean_t zfs_bookmark_exists(const char *path); /* * Mount support functions. diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index e1fa965893..26e5adc02c 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -296,7 +296,7 @@ zpool_handle(zfs_handle_t *zhp) int len; zpool_handle_t *zph; - len = strcspn(zhp->zfs_name, "/@") + 1; + len = strcspn(zhp->zfs_name, "/@#") + 1; pool_name = zfs_alloc(zhp->zfs_hdl, len); (void) strlcpy(pool_name, zhp->zfs_name, len); @@ -568,6 +568,70 @@ zfs_handle_dup(zfs_handle_t *zhp_orig) return (zhp); } +boolean_t +zfs_bookmark_exists(const char *path) +{ + nvlist_t *bmarks; + nvlist_t *props; + char fsname[ZFS_MAXNAMELEN]; + char *bmark_name; + char *pound; + int err; + boolean_t rv; + + + (void) strlcpy(fsname, path, sizeof (fsname)); + pound = strchr(fsname, '#'); + if (pound == NULL) + return (B_FALSE); + + *pound = '\0'; + bmark_name = pound + 1; + props = fnvlist_alloc(); + err = lzc_get_bookmarks(fsname, props, &bmarks); + nvlist_free(props); + if (err != 0) { + nvlist_free(bmarks); + return (B_FALSE); + } + + rv = nvlist_exists(bmarks, bmark_name); + nvlist_free(bmarks); + return (rv); +} + +zfs_handle_t * +make_bookmark_handle(zfs_handle_t *parent, const char *path, + nvlist_t *bmark_props) +{ + zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); + + if (zhp == NULL) + return (NULL); + + /* Fill in the name. */ + zhp->zfs_hdl = parent->zfs_hdl; + (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); + + /* Set the property lists. */ + if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) { + free(zhp); + return (NULL); + } + + /* Set the types. */ + zhp->zfs_head_type = parent->zfs_head_type; + zhp->zfs_type = ZFS_TYPE_BOOKMARK; + + if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) { + nvlist_free(zhp->zfs_props); + free(zhp); + return (NULL); + } + + return (zhp); +} + /* * Opens the given snapshot, filesystem, or volume. The 'types' * argument is a mask of acceptable types. The function will print an @@ -2250,6 +2314,9 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, case ZFS_TYPE_SNAPSHOT: str = "snapshot"; break; + case ZFS_TYPE_BOOKMARK: + str = "bookmark"; + break; default: abort(); } @@ -3100,6 +3167,19 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) { zfs_cmd_t zc = { 0 }; + if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { + nvlist_t *nv = fnvlist_alloc(); + fnvlist_add_boolean(nv, zhp->zfs_name); + int error = lzc_destroy_bookmarks(nv, NULL); + fnvlist_free(nv); + if (error != 0) { + return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, + dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), + zhp->zfs_name)); + } + return (0); + } + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) { @@ -3482,45 +3562,44 @@ typedef struct rollback_data { const char *cb_target; /* the snapshot */ uint64_t cb_create; /* creation time reference */ boolean_t cb_error; - boolean_t cb_dependent; boolean_t cb_force; } rollback_data_t; static int -rollback_destroy(zfs_handle_t *zhp, void *data) +rollback_destroy_dependent(zfs_handle_t *zhp, void *data) { rollback_data_t *cbp = data; + prop_changelist_t *clp; + + /* We must destroy this clone; first unmount it */ + clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, + cbp->cb_force ? MS_FORCE: 0); + if (clp == NULL || changelist_prefix(clp) != 0) { + cbp->cb_error = B_TRUE; + zfs_close(zhp); + return (0); + } + if (zfs_destroy(zhp, B_FALSE) != 0) + cbp->cb_error = B_TRUE; + else + changelist_remove(clp, zhp->zfs_name); + (void) changelist_postfix(clp); + changelist_free(clp); - if (!cbp->cb_dependent) { - if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && - zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && - zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > - cbp->cb_create) { + zfs_close(zhp); + return (0); +} - cbp->cb_dependent = B_TRUE; - cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, - rollback_destroy, cbp); - cbp->cb_dependent = B_FALSE; +static int +rollback_destroy(zfs_handle_t *zhp, void *data) +{ + rollback_data_t *cbp = data; - cbp->cb_error |= zfs_destroy(zhp, B_FALSE); - } - } else { - /* We must destroy this clone; first unmount it */ - prop_changelist_t *clp; + if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { + cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, + rollback_destroy_dependent, cbp); - clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, - cbp->cb_force ? MS_FORCE: 0); - if (clp == NULL || changelist_prefix(clp) != 0) { - cbp->cb_error = B_TRUE; - zfs_close(zhp); - return (0); - } - if (zfs_destroy(zhp, B_FALSE) != 0) - cbp->cb_error = B_TRUE; - else - changelist_remove(clp, zhp->zfs_name); - (void) changelist_postfix(clp); - changelist_free(clp); + cbp->cb_error |= zfs_destroy(zhp, B_FALSE); } zfs_close(zhp); @@ -3531,8 +3610,8 @@ rollback_destroy(zfs_handle_t *zhp, void *data) * Given a dataset, rollback to a specific snapshot, discarding any * data changes since then and making it the active dataset. * - * Any snapshots more recent than the target are destroyed, along with - * their dependents. + * Any snapshots and bookmarks more recent than the target are + * destroyed, along with their dependents (i.e. clones). */ int zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) @@ -3552,7 +3631,8 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) cb.cb_force = force; cb.cb_target = snap->zfs_name; cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); - (void) zfs_iter_children(zhp, rollback_destroy, &cb); + (void) zfs_iter_snapshots(zhp, rollback_destroy, &cb); + (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb); if (cb.cb_error) return (-1); diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h index 62793dcda1..9d98718dcb 100644 --- a/usr/src/lib/libzfs/common/libzfs_impl.h +++ b/usr/src/lib/libzfs/common/libzfs_impl.h @@ -22,7 +22,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #ifndef _LIBZFS_IMPL_H @@ -189,6 +189,8 @@ int create_parents(libzfs_handle_t *, char *, int); boolean_t isa_child_of(const char *dataset, const char *parent); zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *); +zfs_handle_t *make_bookmark_handle(zfs_handle_t *, const char *, + nvlist_t *props); int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **); diff --git a/usr/src/lib/libzfs/common/libzfs_iter.c b/usr/src/lib/libzfs/common/libzfs_iter.c index 0bc89cbf8d..19ac0b2625 100644 --- a/usr/src/lib/libzfs/common/libzfs_iter.c +++ b/usr/src/lib/libzfs/common/libzfs_iter.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ @@ -147,7 +147,8 @@ zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) zfs_handle_t *nzhp; int ret; - if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) + if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT || + zhp->zfs_type == ZFS_TYPE_BOOKMARK) return (0); if (zhp->zfs_hdl->libzfs_cachedprops && @@ -174,6 +175,59 @@ zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) } /* + * Iterate over all bookmarks + */ +int +zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data) +{ + zfs_handle_t *nzhp; + nvlist_t *props = NULL; + nvlist_t *bmarks = NULL; + int err; + + if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0) + return (0); + + /* Setup the requested properties nvlist. */ + props = fnvlist_alloc(); + fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID)); + fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG)); + fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION)); + + /* Allocate an nvlist to hold the bookmarks. */ + bmarks = fnvlist_alloc(); + + if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0) + goto out; + + for (nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL); + pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) { + char name[ZFS_MAXNAMELEN]; + char *bmark_name; + nvlist_t *bmark_props; + + bmark_name = nvpair_name(pair); + bmark_props = fnvpair_value_nvlist(pair); + + (void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name, + bmark_name); + + nzhp = make_bookmark_handle(zhp, name, bmark_props); + if (nzhp == NULL) + continue; + + if ((err = func(nzhp, data)) != 0) + goto out; + } + +out: + fnvlist_free(props); + fnvlist_free(bmarks); + + return (err); +} + +/* * Routines for dealing with the sorted snapshot functionality */ typedef struct zfs_node { @@ -407,13 +461,13 @@ static int iter_dependents_cb(zfs_handle_t *zhp, void *arg) { iter_dependents_arg_t *ida = arg; - int err; + int err = 0; boolean_t first = ida->first; ida->first = B_FALSE; if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { err = zfs_iter_clones(zhp, iter_dependents_cb, ida); - } else { + } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) { iter_stack_frame_t isf; iter_stack_frame_t *f; diff --git a/usr/src/lib/libzfs/common/libzfs_sendrecv.c b/usr/src/lib/libzfs/common/libzfs_sendrecv.c index fefaa0d513..8e0e4e1e6e 100644 --- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c +++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. */ @@ -1609,6 +1609,60 @@ err_out: return (err); } +int +zfs_send_one(zfs_handle_t *zhp, const char *from, int fd) +{ + int err; + libzfs_handle_t *hdl = zhp->zfs_hdl; + + char errbuf[1024]; + (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, + "warning: cannot send '%s'"), zhp->zfs_name); + + err = lzc_send(zhp->zfs_name, from, fd); + if (err != 0) { + switch (errno) { + case EXDEV: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "not an earlier snapshot from the same fs")); + return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); + + case ENOENT: + case ESRCH: + if (lzc_exists(zhp->zfs_name)) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "incremental source (%s) does not exist"), + from); + } + return (zfs_error(hdl, EZFS_NOENT, errbuf)); + + case EBUSY: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "target is busy; if a filesystem, " + "it must not be mounted")); + return (zfs_error(hdl, EZFS_BUSY, errbuf)); + + case EDQUOT: + case EFBIG: + case EIO: + case ENOLINK: + case ENOSPC: + case ENOSTR: + case ENXIO: + case EPIPE: + case ERANGE: + case EFAULT: + case EROFS: + zfs_error_aux(hdl, strerror(errno)); + return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); + + default: + return (zfs_standard_error(hdl, errno, errbuf)); + } + } + return (err != 0); +} + /* * Routines specific to "zfs recv" */ diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index d2ce523cf8..0e10528f9e 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -20,7 +20,7 @@ # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2011 Nexenta Systems, Inc. All rights reserved. -# Copyright (c) 2012 by Delphix. All rights reserved. +# Copyright (c) 2013 by Delphix. All rights reserved. # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # MAPFILE HEADER START @@ -64,6 +64,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { spa_feature_table; zfs_allocatable_devs; zfs_asprintf; + zfs_bookmark_exists; zfs_clone; zfs_close; zfs_create; @@ -87,6 +88,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zfs_is_shared; zfs_is_shared_nfs; zfs_is_shared_smb; + zfs_iter_bookmarks; zfs_iter_children; zfs_iter_dependents; zfs_iter_filesystems; @@ -137,6 +139,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zfs_rollback; zfs_save_arguments; zfs_send; + zfs_send_one; zfs_share; zfs_shareall; zfs_share_nfs; @@ -150,6 +153,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zfs_snapshot_nvl; zfs_spa_version; zfs_spa_version_map; + zfs_standard_error; zfs_type_to_name; zfs_unmount; zfs_unmountall; diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.c b/usr/src/lib/libzfs_core/common/libzfs_core.c index 20d7329677..7653d028a9 100644 --- a/usr/src/lib/libzfs_core/common/libzfs_core.c +++ b/usr/src/lib/libzfs_core/common/libzfs_core.c @@ -439,18 +439,30 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp) } /* - * If fromsnap is NULL, a full (non-incremental) stream will be sent. + * + * "snapname" is the full name of the snapshot to send (e.g. "pool/fs@snap") + * + * If "from" is NULL, a full (non-incremental) stream will be sent. + * If "from" is non-NULL, it must be the full name of a snapshot or + * bookmark to send an incremental from (e.g. "pool/fs@earlier_snap" or + * "pool/fs#earlier_bmark"). If non-NULL, the specified snapshot or + * bookmark must represent an earlier point in the history of "snapname"). + * It can be an earlier snapshot in the same filesystem or zvol as "snapname", + * or it can be the origin of "snapname"'s filesystem, or an earlier + * snapshot in the origin, etc. + * + * "fd" is the file descriptor to write the send stream to. */ int -lzc_send(const char *snapname, const char *fromsnap, int fd) +lzc_send(const char *snapname, const char *from, int fd) { nvlist_t *args; int err; args = fnvlist_alloc(); fnvlist_add_int32(args, "fd", fd); - if (fromsnap != NULL) - fnvlist_add_string(args, "fromsnap", fromsnap); + if (from != NULL) + fnvlist_add_string(args, "fromsnap", from); err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL); nvlist_free(args); return (err); @@ -605,3 +617,97 @@ lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen) } return (err); } + +/* + * Creates bookmarks. + * + * The bookmarks nvlist maps from name of the bookmark (e.g. "pool/fs#bmark") to + * the name of the snapshot (e.g. "pool/fs@snap"). All the bookmarks and + * snapshots must be in the same pool. + * + * The returned results nvlist will have an entry for each bookmark that failed. + * The value will be the (int32) error code. + * + * The return value will be 0 if all bookmarks were created, otherwise it will + * be the errno of a (undetermined) bookmarks that failed. + */ +int +lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist) +{ + nvpair_t *elem; + int error; + char pool[MAXNAMELEN]; + + /* determine the pool name */ + elem = nvlist_next_nvpair(bookmarks, NULL); + if (elem == NULL) + return (0); + (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); + pool[strcspn(pool, "/#")] = '\0'; + + error = lzc_ioctl(ZFS_IOC_BOOKMARK, pool, bookmarks, errlist); + + return (error); +} + +/* + * Retrieve bookmarks. + * + * Retrieve the list of bookmarks for the given file system. The props + * parameter is an nvlist of property names (with no values) that will be + * returned for each bookmark. + * + * The following are valid properties on bookmarks, all of which are numbers + * (represented as uint64 in the nvlist) + * + * "guid" - globally unique identifier of the snapshot it refers to + * "createtxg" - txg when the snapshot it refers to was created + * "creation" - timestamp when the snapshot it refers to was created + * + * The format of the returned nvlist as follows: + * <short name of bookmark> -> { + * <name of property> -> { + * "value" -> uint64 + * } + * } + */ +int +lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks) +{ + return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks)); +} + +/* + * Destroys bookmarks. + * + * The keys in the bmarks nvlist are the bookmarks to be destroyed. + * They must all be in the same pool. Bookmarks are specified as + * <fs>#<bmark>. + * + * Bookmarks that do not exist will be silently ignored. + * + * The return value will be 0 if all bookmarks that existed were destroyed. + * + * Otherwise the return value will be the errno of a (undetermined) bookmark + * that failed, no bookmarks will be destroyed, and the errlist will have an + * entry for each bookmarks that failed. The value in the errlist will be + * the (int32) error code. + */ +int +lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist) +{ + nvpair_t *elem; + int error; + char pool[MAXNAMELEN]; + + /* determine the pool name */ + elem = nvlist_next_nvpair(bmarks, NULL); + if (elem == NULL) + return (0); + (void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); + pool[strcspn(pool, "/#")] = '\0'; + + error = lzc_ioctl(ZFS_IOC_DESTROY_BOOKMARKS, pool, bmarks, errlist); + + return (error); +} diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.h b/usr/src/lib/libzfs_core/common/libzfs_core.h index 3642dc7afd..484a48afe2 100644 --- a/usr/src/lib/libzfs_core/common/libzfs_core.h +++ b/usr/src/lib/libzfs_core/common/libzfs_core.h @@ -38,27 +38,27 @@ extern "C" { int libzfs_core_init(void); void libzfs_core_fini(void); -int lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist); -int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props); -int lzc_clone(const char *fsname, const char *origin, nvlist_t *props); -int lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist); +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_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 **); +int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **); -int lzc_snaprange_space(const char *firstsnap, const char *lastsnap, - uint64_t *usedp); +int lzc_snaprange_space(const char *, const char *, uint64_t *); -int lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist); -int lzc_release(nvlist_t *holds, nvlist_t **errlist); -int lzc_get_holds(const char *snapname, nvlist_t **holdsp); +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_send(const char *snapname, const char *fromsnap, int fd); -int lzc_receive(const char *snapname, nvlist_t *props, const char *origin, - boolean_t force, int fd); -int lzc_send_space(const char *snapname, const char *fromsnap, - uint64_t *result); +int lzc_send(const char *, const char *, int); +int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int); +int lzc_send_space(const char *, const char *, uint64_t *); -boolean_t lzc_exists(const char *dataset); +boolean_t lzc_exists(const char *); -int lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen); +int lzc_rollback(const char *, char *, int); #ifdef __cplusplus } diff --git a/usr/src/lib/libzfs_core/common/mapfile-vers b/usr/src/lib/libzfs_core/common/mapfile-vers index a4a110f907..ebed35cfd0 100644 --- a/usr/src/lib/libzfs_core/common/mapfile-vers +++ b/usr/src/lib/libzfs_core/common/mapfile-vers @@ -41,10 +41,13 @@ SYMBOL_VERSION ILLUMOS_0.1 { libzfs_core_fini; libzfs_core_init; + lzc_bookmark; lzc_clone; lzc_create; + lzc_destroy_bookmarks; lzc_destroy_snaps; lzc_exists; + lzc_get_bookmarks; lzc_get_holds; lzc_hold; lzc_receive; diff --git a/usr/src/lib/pyzfs/common/allow.py b/usr/src/lib/pyzfs/common/allow.py index fa8209f697..7ad4b49cc3 100644 --- a/usr/src/lib/pyzfs/common/allow.py +++ b/usr/src/lib/pyzfs/common/allow.py @@ -20,6 +20,7 @@ # CDDL HEADER END # # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013 by Delphix. All rights reserved. # """This module implements the "zfs allow" and "zfs unallow" subcommands. @@ -219,6 +220,7 @@ perms_subcmd = dict( hold=_("Allows adding a user hold to a snapshot"), release=_("Allows releasing a user hold which\n\t\t\t\tmight destroy the snapshot"), diff=_("Allows lookup of paths within a dataset,\n\t\t\t\tgiven an object number. Ordinary users need this\n\t\t\t\tin order to use zfs diff"), + bookmark="", ) perms_other = dict( |