Index: cddl/contrib/opensolaris/cmd/zfs/zfs_main.c =================================================================== --- cddl/contrib/opensolaris/cmd/zfs/zfs_main.c +++ cddl/contrib/opensolaris/cmd/zfs/zfs_main.c @@ -5472,18 +5472,24 @@ for (i = 0; i < argc; ++i) { zfs_handle_t *zhp; char parent[ZFS_MAXNAMELEN]; - const char *delim; + const char *delim, *snapshot; char *path = argv[i]; delim = strchr(path, '@'); if (delim == NULL) { - (void) fprintf(stderr, - gettext("'%s' is not a snapshot\n"), path); - ++errors; - continue; + if (holding) { + (void) fprintf(stderr, + gettext("'%s' is not a snapshot\n"), path); + ++errors; + continue; + } + (void) strcpy(parent, path); + snapshot = NULL; + } else { + (void) strncpy(parent, path, delim - path); + parent[delim - path] = '\0'; + snapshot = delim + 1; } - (void) strncpy(parent, path, delim - path); - parent[delim - path] = '\0'; zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); @@ -5492,10 +5498,10 @@ continue; } if (holding) { - if (zfs_hold(zhp, delim+1, tag, recursive, -1) != 0) + if (zfs_hold(zhp, snapshot, tag, recursive, -1) != 0) ++errors; } else { - if (zfs_release(zhp, delim+1, tag, recursive) != 0) + if (zfs_release(zhp, snapshot, tag, recursive) != 0) ++errors; } zfs_close(zhp); Index: cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c =================================================================== --- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -4549,8 +4549,40 @@ { struct holdarg *ha = arg; char name[ZFS_MAXNAMELEN]; - int rv = 0; + int rv = 0, rvs = 0; nvlist_t *existing_holds; + nvpair_t *nvp = NULL; + + if (ha->snapname == NULL) { + if (lzc_get_holds(zhp->zfs_name, &existing_holds) != 0) { + ha->error = ENOENT; + } else { + while ((nvp = nvlist_next_nvpair(existing_holds, nvp)) + != NULL) { + const char *zname = zfs_get_name(zhp); + const char *tag = nvpair_name(nvp); + nvlist_t *torelease = fnvlist_alloc(); + + if (strcmp(ha->tag, tag) == 0) { + fnvlist_add_boolean(torelease, ha->tag); + fnvlist_add_nvlist(ha->nvl, zname, torelease); + fnvlist_free(torelease); + } + } + } + + if (!nvlist_exists(existing_holds, ha->tag)) + ha->error = ESRCH; + + if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) { + rvs = zfs_iter_snapshots(zhp, B_FALSE, zfs_release_one, ha); + if (ha->recursive) + rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); + } + + zfs_close(zhp); + return (rv + rvs); + } (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, ha->snapname); @@ -4593,10 +4625,17 @@ if (nvlist_empty(ha.nvl)) { fnvlist_free(ha.nvl); ret = ha.error; - (void) snprintf(errbuf, sizeof (errbuf), - dgettext(TEXT_DOMAIN, - "cannot release hold from snapshot '%s@%s'"), - zhp->zfs_name, snapname); + if (snapname == NULL) { + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, + "cannot release holds from '%s'"), + zhp->zfs_name); + } else { + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, + "cannot release hold from snapshot '%s@%s'"), + zhp->zfs_name, snapname); + } if (ret == ESRCH) { (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf); } else {