zfs userspace: support recursing through child datasets
Recurse through child datasets and return the sum of space used by each user or group. use ZFS_ITER_ARGS_CAN_BE_PATHS so a dataset can be specified by its name or mountpoint Signed-off-by: Allan Jude <allanjude@freebsd.org>
This commit is contained in:
parent
345196be18
commit
72fdcaa68c
|
@ -358,18 +358,18 @@ get_usage(zfs_help_t idx)
|
|||
"\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
|
||||
"<filesystem|volume>\n"));
|
||||
case HELP_USERSPACE:
|
||||
return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
|
||||
"[-s field] ...\n"
|
||||
return (gettext("\tuserspace [-Hinpr] [-d depth] "
|
||||
"[-o field[,...]] [-s field] ...\n"
|
||||
"\t [-S field] ... [-t type[,...]] "
|
||||
"<filesystem|snapshot|path>\n"));
|
||||
case HELP_GROUPSPACE:
|
||||
return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
|
||||
"[-s field] ...\n"
|
||||
return (gettext("\tgroupspace [-Hinpr] [-d depth] "
|
||||
"[-o field[,...]] [-s field] ...\n"
|
||||
"\t [-S field] ... [-t type[,...]] "
|
||||
"<filesystem|snapshot|path>\n"));
|
||||
case HELP_PROJECTSPACE:
|
||||
return (gettext("\tprojectspace [-Hp] [-o field[,...]] "
|
||||
"[-s field] ... \n"
|
||||
return (gettext("\tprojectspace [-Hpr] [-d depth] "
|
||||
"[-o field[,...]] [-s field] ... \n"
|
||||
"\t [-S field] ... <filesystem|snapshot|path>\n"));
|
||||
case HELP_PROJECT:
|
||||
return (gettext("\tproject [-d|-r] <directory|file ...>\n"
|
||||
|
@ -2625,13 +2625,13 @@ zfs_do_upgrade(int argc, char **argv)
|
|||
}
|
||||
|
||||
/*
|
||||
* zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
|
||||
* zfs userspace [-Hinpr]] [-d depth] [-o field[,...]] [-s field [-s field]...]
|
||||
* [-S field [-S field]...] [-t type[,...]]
|
||||
* filesystem | snapshot | path
|
||||
* zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
|
||||
* zfs groupspace [-Hinpr]] [-d depth] [-o field[,...]] [-s field [-s field]...]
|
||||
* [-S field [-S field]...] [-t type[,...]]
|
||||
* filesystem | snapshot | path
|
||||
* zfs projectspace [-Hp] [-o field[,...]] [-s field [-s field]...]
|
||||
* zfs projectspace [-Hpr]] [-d depth] [-o field[,...]] [-s field [-s field]...]
|
||||
* [-S field [-S field]...] filesystem | snapshot | path
|
||||
*
|
||||
* -H Scripted mode; elide headers and separate columns by tabs.
|
||||
|
@ -2639,6 +2639,8 @@ zfs_do_upgrade(int argc, char **argv)
|
|||
* -n Print numeric ID instead of user/group name.
|
||||
* -o Control which fields to display.
|
||||
* -p Use exact (parsable) numeric output.
|
||||
* -r Recursive over children of the dataset as well.
|
||||
* -d Limit depth of recursion
|
||||
* -s Specify sort columns, descending order.
|
||||
* -S Specify sort columns, ascending order.
|
||||
* -t Control which object types to display.
|
||||
|
@ -2699,6 +2701,12 @@ typedef struct us_cbdata {
|
|||
size_t cb_width[USFIELD_LAST];
|
||||
} us_cbdata_t;
|
||||
|
||||
typedef struct us_cb_recurse {
|
||||
int types;
|
||||
zfs_userspace_cb_t zfs_us_cb;
|
||||
us_cbdata_t *cb;
|
||||
} us_cb_recurse_t;
|
||||
|
||||
static boolean_t us_populated = B_FALSE;
|
||||
|
||||
typedef struct {
|
||||
|
@ -2850,6 +2858,36 @@ us_type2str(unsigned field_type)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
userspace_recurse_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
us_cb_recurse_t *usrcb = (us_cb_recurse_t *)arg;
|
||||
zfs_userquota_prop_t p;
|
||||
int ret;
|
||||
|
||||
if (zfs_get_underlying_type(zhp) != ZFS_TYPE_FILESYSTEM) {
|
||||
(void) fprintf(stderr, gettext("operation is only applicable "
|
||||
"to filesystems and their snapshots\n"));
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
|
||||
if ((zfs_prop_is_user(p) &&
|
||||
!(usrcb->types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
|
||||
(zfs_prop_is_group(p) &&
|
||||
!(usrcb->types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))) ||
|
||||
(zfs_prop_is_project(p) && usrcb->types != USTYPE_PROJ))
|
||||
continue;
|
||||
|
||||
usrcb->cb->cb_prop = p;
|
||||
if ((ret = zfs_userspace(zhp, p, usrcb->zfs_us_cb,
|
||||
usrcb->cb)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
|
||||
{
|
||||
|
@ -2975,34 +3013,6 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
|
|||
if (nameidx >= 0 && namelen > cb->cb_width[nameidx])
|
||||
cb->cb_width[nameidx] = namelen;
|
||||
|
||||
/*
|
||||
* Check if this type/name combination is in the list and update it;
|
||||
* otherwise add new node to the list.
|
||||
*/
|
||||
if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
|
||||
uu_avl_insert(avl, node, idx);
|
||||
} else {
|
||||
nvlist_free(props);
|
||||
free(node);
|
||||
node = n;
|
||||
props = node->usn_nvl;
|
||||
}
|
||||
|
||||
/* Calculate/update width of USED/QUOTA fields */
|
||||
if (cb->cb_nicenum) {
|
||||
if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
|
||||
prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA ||
|
||||
prop == ZFS_PROP_PROJECTUSED ||
|
||||
prop == ZFS_PROP_PROJECTQUOTA) {
|
||||
zfs_nicebytes(space, sizebuf, sizeof (sizebuf));
|
||||
} else {
|
||||
zfs_nicenum(space, sizebuf, sizeof (sizebuf));
|
||||
}
|
||||
} else {
|
||||
(void) snprintf(sizebuf, sizeof (sizebuf), "%llu",
|
||||
(u_longlong_t)space);
|
||||
}
|
||||
sizelen = strlen(sizebuf);
|
||||
if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
|
||||
prop == ZFS_PROP_PROJECTUSED) {
|
||||
propname = "used";
|
||||
|
@ -3027,6 +3037,39 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
|
|||
} else {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this type/name combination is in the list and update it;
|
||||
* otherwise add new node to the list.
|
||||
*/
|
||||
if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
|
||||
uu_avl_insert(avl, node, idx);
|
||||
} else {
|
||||
uint64_t oldspace = 0;
|
||||
|
||||
if (nvlist_lookup_uint64(n->usn_nvl, propname, &oldspace) == 0)
|
||||
space += oldspace;
|
||||
nvlist_free(props);
|
||||
free(node);
|
||||
node = n;
|
||||
props = node->usn_nvl;
|
||||
}
|
||||
|
||||
/* Calculate/update width of USED/QUOTA fields */
|
||||
if (cb->cb_nicenum) {
|
||||
if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
|
||||
prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA ||
|
||||
prop == ZFS_PROP_PROJECTUSED ||
|
||||
prop == ZFS_PROP_PROJECTQUOTA) {
|
||||
zfs_nicebytes(space, sizebuf, sizeof (sizebuf));
|
||||
} else {
|
||||
zfs_nicenum(space, sizebuf, sizeof (sizebuf));
|
||||
}
|
||||
} else {
|
||||
(void) snprintf(sizebuf, sizeof (sizebuf), "%llu",
|
||||
(u_longlong_t)space);
|
||||
}
|
||||
sizelen = strlen(sizebuf);
|
||||
sizeidx = us_field_index(propname);
|
||||
if (sizeidx >= 0 && sizelen > cb->cb_width[sizeidx])
|
||||
cb->cb_width[sizeidx] = sizelen;
|
||||
|
@ -3189,7 +3232,6 @@ static int
|
|||
zfs_do_userspace(int argc, char **argv)
|
||||
{
|
||||
zfs_handle_t *zhp;
|
||||
zfs_userquota_prop_t p;
|
||||
uu_avl_pool_t *avl_pool;
|
||||
uu_avl_t *avl_tree;
|
||||
uu_avl_walk_t *walk;
|
||||
|
@ -3199,6 +3241,8 @@ zfs_do_userspace(int argc, char **argv)
|
|||
char *tfield = NULL;
|
||||
int cfield = 0;
|
||||
int fields[256];
|
||||
int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
|
||||
int limit = 0;
|
||||
int i;
|
||||
boolean_t scripted = B_FALSE;
|
||||
boolean_t prtnum = B_FALSE;
|
||||
|
@ -3209,6 +3253,7 @@ zfs_do_userspace(int argc, char **argv)
|
|||
zfs_sort_column_t *sortcol = NULL;
|
||||
int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
|
||||
us_cbdata_t cb;
|
||||
us_cb_recurse_t usrcb;
|
||||
us_node_t *node;
|
||||
us_node_t *rmnode;
|
||||
uu_list_pool_t *listpool;
|
||||
|
@ -3227,8 +3272,11 @@ zfs_do_userspace(int argc, char **argv)
|
|||
prtnum = B_TRUE;
|
||||
}
|
||||
|
||||
while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
|
||||
while ((c = getopt(argc, argv, "d:nHpo:rs:S:t:i")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
limit = parse_depth(optarg, &flags);
|
||||
break;
|
||||
case 'n':
|
||||
if (types == USTYPE_PROJ) {
|
||||
(void) fprintf(stderr,
|
||||
|
@ -3246,6 +3294,9 @@ zfs_do_userspace(int argc, char **argv)
|
|||
case 'o':
|
||||
ofield = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
flags |= ZFS_ITER_RECURSE;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
if (zfs_add_sort_column(&sortcol, optarg,
|
||||
|
@ -3358,6 +3409,10 @@ zfs_do_userspace(int argc, char **argv)
|
|||
(void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
|
||||
(void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
|
||||
|
||||
usrcb.types = types;
|
||||
usrcb.zfs_us_cb = userspace_cb;
|
||||
usrcb.cb = &cb;
|
||||
|
||||
cb.cb_sortcol = sortcol;
|
||||
cb.cb_numname = prtnum;
|
||||
cb.cb_nicenum = !parsable;
|
||||
|
@ -3368,21 +3423,8 @@ zfs_do_userspace(int argc, char **argv)
|
|||
for (i = 0; i < USFIELD_LAST; i++)
|
||||
cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
|
||||
|
||||
for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
|
||||
if ((zfs_prop_is_user(p) &&
|
||||
!(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
|
||||
(zfs_prop_is_group(p) &&
|
||||
!(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))) ||
|
||||
(zfs_prop_is_project(p) && types != USTYPE_PROJ))
|
||||
continue;
|
||||
|
||||
cb.cb_prop = p;
|
||||
if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
zfs_close(zhp);
|
||||
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM, NULL, NULL,
|
||||
limit, userspace_recurse_cb, &usrcb);
|
||||
|
||||
/* Sort the list */
|
||||
if ((node = uu_avl_first(avl_tree)) == NULL)
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
.Sh SYNOPSIS
|
||||
.Nm zfs
|
||||
.Cm userspace
|
||||
.Op Fl Hinp
|
||||
.Op Fl Hinpr
|
||||
.Op Fl d Ar depth
|
||||
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns … Oc
|
||||
.Oo Fl s Ar field Oc Ns …
|
||||
.Oo Fl S Ar field Oc Ns …
|
||||
|
@ -47,7 +48,8 @@
|
|||
.Ar filesystem Ns | Ns Ar snapshot Ns | Ns Ar path
|
||||
.Nm zfs
|
||||
.Cm groupspace
|
||||
.Op Fl Hinp
|
||||
.Op Fl Hinpr
|
||||
.Op Fl d Ar depth
|
||||
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns … Oc
|
||||
.Oo Fl s Ar field Oc Ns …
|
||||
.Oo Fl S Ar field Oc Ns …
|
||||
|
@ -55,7 +57,8 @@
|
|||
.Ar filesystem Ns | Ns Ar snapshot Ns | Ns Ar path
|
||||
.Nm zfs
|
||||
.Cm projectspace
|
||||
.Op Fl Hp
|
||||
.Op Fl Hpr
|
||||
.Op Fl d Ar depth
|
||||
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns … Oc
|
||||
.Oo Fl s Ar field Oc Ns …
|
||||
.Oo Fl S Ar field Oc Ns …
|
||||
|
@ -66,7 +69,8 @@
|
|||
.It Xo
|
||||
.Nm zfs
|
||||
.Cm userspace
|
||||
.Op Fl Hinp
|
||||
.Op Fl Hinpr
|
||||
.Op Fl d Ar depth
|
||||
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns … Oc
|
||||
.Oo Fl s Ar field Oc Ns …
|
||||
.Oo Fl S Ar field Oc Ns …
|
||||
|
@ -90,6 +94,10 @@ Do not print headers, use tab-delimited output.
|
|||
Sort by this field in reverse order.
|
||||
See
|
||||
.Fl s .
|
||||
.It Fl d Ar depth
|
||||
Calculate the sum of usage for the specified filesystem, snapshot,
|
||||
or path and any of its children, limiting the recursion to
|
||||
.Ar depth .
|
||||
.It Fl i
|
||||
Translate SID to POSIX ID.
|
||||
The POSIX ID may be ephemeral if no mapping exists.
|
||||
|
@ -122,6 +130,9 @@ The default is to display all fields.
|
|||
Use exact
|
||||
.Pq parsable
|
||||
numeric output.
|
||||
.It Fl r
|
||||
Recursively calculate the sum of usage for the specified
|
||||
filesystem, snapshot, or path and any of its children.
|
||||
.It Fl s Ar field
|
||||
Sort output by this field.
|
||||
The
|
||||
|
@ -146,7 +157,8 @@ The default can be changed to include group types.
|
|||
.It Xo
|
||||
.Nm zfs
|
||||
.Cm groupspace
|
||||
.Op Fl Hinp
|
||||
.Op Fl Hinpr
|
||||
.Op Fl d Ar depth
|
||||
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns … Oc
|
||||
.Oo Fl s Ar field Oc Ns …
|
||||
.Oo Fl S Ar field Oc Ns …
|
||||
|
@ -162,7 +174,8 @@ except that the default types to display are
|
|||
.It Xo
|
||||
.Nm zfs
|
||||
.Cm projectspace
|
||||
.Op Fl Hp
|
||||
.Op Fl Hpr
|
||||
.Op Fl d Ar depth
|
||||
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns … Oc
|
||||
.Oo Fl s Ar field Oc Ns …
|
||||
.Oo Fl S Ar field Oc Ns …
|
||||
|
|
Loading…
Reference in New Issue