diff options
author | ahrens <none@none> | 2006-06-14 23:16:39 -0700 |
---|---|---|
committer | ahrens <none@none> | 2006-06-14 23:16:39 -0700 |
commit | 1d452cf5123cb6ac0a013a4dbd4dcceeb0da314d (patch) | |
tree | 4c6acabeb0476b9d46ef194f560e953da44094b0 /usr/src/lib/libzfs | |
parent | 7a0b67e3ef0ce92ca436e68c45383a76e14311a0 (diff) | |
download | illumos-joyent-1d452cf5123cb6ac0a013a4dbd4dcceeb0da314d.tar.gz |
PSARC 2006/388 snapshot -r
6373978 want to take lots of snapshots quickly ('zfs snapshot -r')
Diffstat (limited to 'usr/src/lib/libzfs')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_dataset.c | 149 | ||||
-rw-r--r-- | usr/src/lib/libzfs/spec/libzfs.spec | 4 |
3 files changed, 132 insertions, 24 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 410649bdcb..dcaccba2d3 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -284,8 +284,9 @@ extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t, const char *, const char *); extern int zfs_destroy(zfs_handle_t *); +extern int zfs_destroy_snaps(zfs_handle_t *, char *); extern int zfs_clone(zfs_handle_t *, const char *); -extern int zfs_snapshot(libzfs_handle_t *, const char *); +extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t); extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, int); extern int zfs_rename(zfs_handle_t *, const char *); extern int zfs_send(zfs_handle_t *, zfs_handle_t *); diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index 9ff3a083be..148bacdcaf 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -169,6 +169,13 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) return (0); } + if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { + if (hdl != NULL) + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "missing '@' delimeter in snapshot name")); + return (0); + } + return (-1); } @@ -1943,7 +1950,6 @@ zfs_destroy(zfs_handle_t *zhp) { zfs_cmd_t zc = { 0 }; int ret; - char errbuf[1024]; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); @@ -1961,20 +1967,95 @@ zfs_destroy(zfs_handle_t *zhp) } ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); - - (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, - "cannot destroy '%s'"), zhp->zfs_name); - - if (ret != 0) + if (ret != 0) { return (zfs_standard_error(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), zhp->zfs_name)); + } remove_mountpoint(zhp); return (0); } +struct destroydata { + char *snapname; + boolean_t gotone; +}; + +static int +zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) +{ + struct destroydata *dd = arg; + zfs_handle_t *szhp; + char name[ZFS_MAXNAMELEN]; + + (void) strcpy(name, zhp->zfs_name); + (void) strcat(name, "@"); + (void) strcat(name, dd->snapname); + + szhp = make_dataset_handle(zhp->zfs_hdl, name); + if (szhp) { + dd->gotone = B_TRUE; + zfs_close(szhp); + } + + if (zhp->zfs_type == ZFS_TYPE_VOLUME) { + (void) zvol_remove_link(zhp->zfs_hdl, name); + /* + * NB: this is simply a best-effort. We don't want to + * return an error, because then we wouldn't visit all + * the volumes. + */ + } + + return (zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg)); +} + +/* + * Destroys all snapshots with the given name in zhp & descendants. + */ +int +zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname) +{ + zfs_cmd_t zc = { 0 }; + int ret; + struct destroydata dd = { 0 }; + + dd.snapname = snapname; + (void) zfs_remove_link_cb(zhp, &dd); + + if (!dd.gotone) { + return (zfs_standard_error(zhp->zfs_hdl, ENOENT, + dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), + zhp->zfs_name, snapname)); + } + + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + (void) strlcpy(zc.zc_prop_value, snapname, sizeof (zc.zc_prop_value)); + + ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); + if (ret != 0) { + char errbuf[1024]; + + (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, + "cannot destroy '%s@%s'"), zc.zc_name, snapname); + + switch (errno) { + case EEXIST: + zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, + "snapshot is cloned")); + return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); + + default: + return (zfs_standard_error(zhp->zfs_hdl, errno, + errbuf)); + } + } + + return (0); +} + /* * Clones the given dataset. The target must be of the same type as the source. */ @@ -2171,11 +2252,32 @@ zfs_promote(zfs_handle_t *zhp) return (ret); } +static int +zfs_create_link_cb(zfs_handle_t *zhp, void *arg) +{ + char *snapname = arg; + + if (zhp->zfs_type == ZFS_TYPE_VOLUME) { + char name[MAXPATHLEN]; + + (void) strcpy(name, zhp->zfs_name); + (void) strcat(name, "@"); + (void) strcat(name, snapname); + (void) zvol_create_link(zhp->zfs_hdl, name); + /* + * NB: this is simply a best-effort. We don't want to + * return an error, because then we wouldn't visit all + * the volumes. + */ + } + return (zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname)); +} + /* * Takes a snapshot of the given dataset */ int -zfs_snapshot(libzfs_handle_t *hdl, const char *path) +zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) { const char *delim; char *parent; @@ -2191,14 +2293,8 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path) if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); - /* make sure we have a snapshot */ - if ((delim = strchr(path, '@')) == NULL) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "missing '@' delimeter in snapshot name")); - return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); - } - /* make sure the parent exists and is of the appropriate type */ + delim = strchr(path, '@'); if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) return (-1); (void) strncpy(parent, path, delim - path); @@ -2210,20 +2306,27 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path) return (-1); } - (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); - - if (zhp->zfs_type == ZFS_TYPE_VOLUME) - zc.zc_objset_type = DMU_OST_ZVOL; - else - zc.zc_objset_type = DMU_OST_ZFS; - - ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + (void) strlcpy(zc.zc_prop_value, delim+1, sizeof (zc.zc_prop_value)); + zc.zc_cookie = recursive; + ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); + /* + * if it was recursive, the one that actually failed will be in + * zc.zc_name. + */ + (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, + "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_prop_value); + if (ret == 0 && recursive) { + (void) zfs_iter_filesystems(zhp, + zfs_create_link_cb, (char *)delim+1); + } if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { ret = zvol_create_link(zhp->zfs_hdl, path); - if (ret != 0) + if (ret != 0) { (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); + } } if (ret != 0) diff --git a/usr/src/lib/libzfs/spec/libzfs.spec b/usr/src/lib/libzfs/spec/libzfs.spec index 6120603e18..0ebb03f0b8 100644 --- a/usr/src/lib/libzfs/spec/libzfs.spec +++ b/usr/src/lib/libzfs/spec/libzfs.spec @@ -64,6 +64,10 @@ function zfs_destroy version SUNWprivate_1.1 end +function zfs_destroy_snaps +version SUNWprivate_1.1 +end + function zfs_get_handle version SUNWprivate_1.1 end |