diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index f1d686753c..64c96da3ff 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -6407,6 +6407,7 @@ zfs_do_release(int argc, char **argv) typedef struct holds_cbdata { boolean_t cb_recursive; + boolean_t cb_all; const char *cb_snapname; nvlist_t **cb_nvlp; size_t cb_max_namelen; @@ -6486,7 +6487,7 @@ holds_callback(zfs_handle_t *zhp, void *data) return (0); snapname = delim + 1; - if (strcmp(cbp->cb_snapname, snapname)) + if (!cbp->cb_all && strcmp(cbp->cb_snapname, snapname) != 0) return (0); } @@ -6564,17 +6565,24 @@ zfs_do_holds(int argc, char **argv) delim = strchr(snapshot, '@'); if (delim == NULL) { - (void) fprintf(stderr, - gettext("'%s' is not a snapshot\n"), snapshot); - errors = B_TRUE; - continue; + if (!recursive) { + (void) fprintf(stderr, + gettext("'%s' is not a snapshot\n"), + snapshot); + errors = B_TRUE; + continue; + } else { + cb.cb_all = B_TRUE; + cb.cb_snapname = NULL; + } + } else { + snapname = delim + 1; + if (recursive) + snapshot[delim - snapshot] = '\0'; + cb.cb_all = B_FALSE; + cb.cb_snapname = snapname; } - snapname = delim + 1; - if (recursive) - snapshot[delim - snapshot] = '\0'; - cb.cb_recursive = recursive; - cb.cb_snapname = snapname; cb.cb_nvlp = &nvl; /* diff --git a/man/man8/zfs-hold.8 b/man/man8/zfs-hold.8 index c2c7b7dc26..04e7660496 100644 --- a/man/man8/zfs-hold.8 +++ b/man/man8/zfs-hold.8 @@ -89,6 +89,21 @@ Do not print headers, use tab-delimited output. .El .It Xo .Nm zfs +.Cm holds +.Fl r +.Op Fl H +.Ar dataset Ns … +.Xc +Lists all existing user references for all snapshots of the given datasets and +their descendants. +.Bl -tag -width "-r" +.It Fl r +Recursive operation, mandatory for dataset arguments. +.It Fl H +Do not print headers, use tab-delimited output. +.El +.It Xo +.Nm zfs .Cm release .Op Fl r .Ar tag Ar snapshot Ns …