Skip to content

Commit

Permalink
Add support for user/group dnode accounting & quota
Browse files Browse the repository at this point in the history
This patch tracks dnode usage for each user/group in the
DMU_USER/GROUPUSED_OBJECT ZAPs. ZAP entries dedicated to dnode
accounting have the key prefixed with "dn-" followed by the UID/GID
in string format (as done for the block accounting).
A new SPA feature has been added for dnode accounting as well as
a new ZPL version. The SPA feature must be enabled in the pool
before upgrading the zfs filesystem. During the zfs version upgrade,
a "quotacheck" will be executed by marking all dnode as dirty.

ZoL-bug-id: #3500

Signed-off-by: Johann Lombardi <[email protected]>
Signed-off-by: Jinshan Xiong <[email protected]>
Change-Id: I899ff446cbf2aa7e355e7d98a83d614f1cd4624b
  • Loading branch information
Jinshan Xiong committed Nov 4, 2015
1 parent b23d543 commit 29e8c12
Show file tree
Hide file tree
Showing 17 changed files with 259 additions and 24 deletions.
4 changes: 3 additions & 1 deletion cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1934,11 +1934,13 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
}

if (verbosity >= 4) {
(void) printf("\tdnode flags: %s%s%s\n",
(void) printf("\tdnode flags: %s%s%s%s\n",
(dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES) ?
"USED_BYTES " : "",
(dn->dn_phys->dn_flags & DNODE_FLAG_USERUSED_ACCOUNTED) ?
"USERUSED_ACCOUNTED " : "",
(dn->dn_phys->dn_flags & DNODE_FLAG_USERDNUSED_ACCOUNTED) ?
"USERDNUSED_ACCOUNTED " : "",
(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ?
"SPILL_BLKPTR" : "");
(void) printf("\tdnode maxblkid: %llu\n",
Expand Down
33 changes: 31 additions & 2 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2119,6 +2119,7 @@ zfs_do_upgrade(int argc, char **argv)
(void) printf(gettext(" 4 userquota, groupquota "
"properties\n"));
(void) printf(gettext(" 5 System attributes\n"));
(void) printf(gettext(" 6 user/group dnode quota\n"));
(void) printf(gettext("\nFor more information on a particular "
"version, including supported releases,\n"));
(void) printf("see the ZFS Administration Guide.\n\n");
Expand Down Expand Up @@ -2801,11 +2802,14 @@ zfs_do_userspace(int argc, char **argv)
cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));

for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
if (((p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA) &&
if (((p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA ||
p == ZFS_PROP_USERDNUSED || p == ZFS_PROP_USERDNQUOTA) &&
!(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
((p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) &&
((p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA ||
p == ZFS_PROP_GROUPDNUSED || p == ZFS_PROP_GROUPDNQUOTA) &&
!(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))))
continue;

cb.cb_prop = p;
if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0)
return (ret);
Expand Down Expand Up @@ -3948,6 +3952,11 @@ zfs_do_receive(int argc, char **argv)
#define ZFS_DELEG_PERM_GROUPQUOTA "groupquota"
#define ZFS_DELEG_PERM_USERUSED "userused"
#define ZFS_DELEG_PERM_GROUPUSED "groupused"
#define ZFS_DELEG_PERM_USERDNQUOTA "userdnquota"
#define ZFS_DELEG_PERM_GROUPDNQUOTA "groupdnquota"
#define ZFS_DELEG_PERM_USERDNUSED "userdnused"
#define ZFS_DELEG_PERM_GROUPDNUSED "groupdnused"

#define ZFS_DELEG_PERM_HOLD "hold"
#define ZFS_DELEG_PERM_RELEASE "release"
#define ZFS_DELEG_PERM_DIFF "diff"
Expand Down Expand Up @@ -3978,6 +3987,10 @@ static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
{ ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP },
{ ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA },
{ ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED },
{ ZFS_DELEG_PERM_USERDNQUOTA, ZFS_DELEG_NOTE_USERDNQUOTA },
{ ZFS_DELEG_PERM_USERDNUSED, ZFS_DELEG_NOTE_USERDNUSED },
{ ZFS_DELEG_PERM_GROUPDNQUOTA, ZFS_DELEG_NOTE_GROUPDNQUOTA },
{ ZFS_DELEG_PERM_GROUPDNUSED, ZFS_DELEG_NOTE_GROUPDNUSED },
{ NULL, ZFS_DELEG_NOTE_NONE }
};

Expand Down Expand Up @@ -4055,6 +4068,10 @@ deleg_perm_type(zfs_deleg_note_t note)
case ZFS_DELEG_NOTE_USERPROP:
case ZFS_DELEG_NOTE_USERQUOTA:
case ZFS_DELEG_NOTE_USERUSED:
case ZFS_DELEG_NOTE_USERDNQUOTA:
case ZFS_DELEG_NOTE_USERDNUSED:
case ZFS_DELEG_NOTE_GROUPDNQUOTA:
case ZFS_DELEG_NOTE_GROUPDNUSED:
/* other */
return (gettext("other"));
default:
Expand Down Expand Up @@ -4558,6 +4575,18 @@ deleg_perm_comment(zfs_deleg_note_t note)
case ZFS_DELEG_NOTE_USERUSED:
str = gettext("Allows reading any userused@... property");
break;
case ZFS_DELEG_NOTE_USERDNQUOTA:
str = gettext("Allows accessing any userdnquota@... property");
break;
case ZFS_DELEG_NOTE_GROUPDNQUOTA:
str = gettext("Allows accessing any groupdnquota@... property");
break;
case ZFS_DELEG_NOTE_GROUPDNUSED:
str = gettext("Allows reading any groupdnused@... property");
break;
case ZFS_DELEG_NOTE_USERDNUSED:
str = gettext("Allows reading any userdnused@... property");
break;
/* other */
default:
str = "";
Expand Down
4 changes: 4 additions & 0 deletions include/sys/dmu_objset.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct dmu_tx;
(arc_buf_size(buf) > OBJSET_OLD_PHYS_SIZE)

#define OBJSET_FLAG_USERACCOUNTING_COMPLETE (1ULL<<0)
#define OBJSET_FLAG_USERDNACCOUNTING_COMPLETE (1ULL<<1)

typedef struct objset_phys {
dnode_phys_t os_meta_dnode;
Expand Down Expand Up @@ -172,6 +173,9 @@ void dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx);
boolean_t dmu_objset_userused_enabled(objset_t *os);
int dmu_objset_userspace_upgrade(objset_t *os);
boolean_t dmu_objset_userspace_present(objset_t *os);
boolean_t dmu_objset_userdnused_enabled(objset_t *os);
int dmu_objset_userdnspace_upgrade(objset_t *os);
boolean_t dmu_objset_userdnspace_present(objset_t *os);
int dmu_fsname(const char *snapname, char *buf);

void dmu_objset_evict_done(objset_t *os);
Expand Down
3 changes: 3 additions & 0 deletions include/sys/dnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ enum dnode_dirtycontext {
/* Does dnode have a SA spill blkptr in bonus? */
#define DNODE_FLAG_SPILL_BLKPTR (1<<2)

/* User/Group dnode accounting */
#define DNODE_FLAG_USERDNUSED_ACCOUNTED (1<<3)

typedef struct dnode_phys {
uint8_t dn_type; /* dmu_object_type_t */
uint8_t dn_indblkshift; /* ln2(indirect block size) */
Expand Down
4 changes: 4 additions & 0 deletions include/sys/dsl_deleg.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ extern "C" {
#define ZFS_DELEG_PERM_VSCAN "vscan"
#define ZFS_DELEG_PERM_USERQUOTA "userquota"
#define ZFS_DELEG_PERM_GROUPQUOTA "groupquota"
#define ZFS_DELEG_PERM_USERDNQUOTA "userdnquota"
#define ZFS_DELEG_PERM_GROUPDNQUOTA "groupdnquota"
#define ZFS_DELEG_PERM_USERUSED "userused"
#define ZFS_DELEG_PERM_GROUPUSED "groupused"
#define ZFS_DELEG_PERM_USERDNUSED "userdnused"
#define ZFS_DELEG_PERM_GROUPDNUSED "groupdnused"
#define ZFS_DELEG_PERM_HOLD "hold"
#define ZFS_DELEG_PERM_RELEASE "release"
#define ZFS_DELEG_PERM_DIFF "diff"
Expand Down
5 changes: 5 additions & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ typedef enum {
ZFS_PROP_USERQUOTA,
ZFS_PROP_GROUPUSED,
ZFS_PROP_GROUPQUOTA,
ZFS_PROP_USERDNUSED,
ZFS_PROP_USERDNQUOTA,
ZFS_PROP_GROUPDNUSED,
ZFS_PROP_GROUPDNQUOTA,
ZFS_NUM_USERQUOTA_PROPS
} zfs_userquota_prop_t;

Expand Down Expand Up @@ -884,6 +888,7 @@ typedef enum zfs_ioc {
ZFS_IOC_BOOKMARK,
ZFS_IOC_GET_BOOKMARKS,
ZFS_IOC_DESTROY_BOOKMARKS,
ZFS_IOC_USERDNSPACE_UPGRADE,

/*
* Linux - 3/64 numbers reserved.
Expand Down
2 changes: 2 additions & 0 deletions include/sys/zfs_vfsops.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ typedef struct zfs_sb {
kmutex_t z_lock;
uint64_t z_userquota_obj;
uint64_t z_groupquota_obj;
uint64_t z_userdnquota_obj;
uint64_t z_groupdnquota_obj;
uint64_t z_replay_eof; /* New end of file - replay only */
sa_attr_type_t *z_attr_table; /* SA attr mapping->id */
#define ZFS_OBJ_MTX_SZ 256
Expand Down
1 change: 1 addition & 0 deletions include/zfeature_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ typedef enum spa_feature {
SPA_FEATURE_BOOKMARKS,
SPA_FEATURE_FS_SS_LIMIT,
SPA_FEATURE_LARGE_BLOCKS,
SPA_FEATURE_USERDN_ACCOUNTING,
SPA_FEATURES
} spa_feature_t;

Expand Down
4 changes: 4 additions & 0 deletions include/zfs_deleg.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ typedef enum {
ZFS_DELEG_NOTE_GROUPQUOTA,
ZFS_DELEG_NOTE_USERUSED,
ZFS_DELEG_NOTE_GROUPUSED,
ZFS_DELEG_NOTE_USERDNQUOTA,
ZFS_DELEG_NOTE_GROUPDNQUOTA,
ZFS_DELEG_NOTE_USERDNUSED,
ZFS_DELEG_NOTE_GROUPDNUSED,
ZFS_DELEG_NOTE_HOLD,
ZFS_DELEG_NOTE_RELEASE,
ZFS_DELEG_NOTE_DIFF,
Expand Down
15 changes: 11 additions & 4 deletions lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,9 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}

if (uqtype != ZFS_PROP_USERQUOTA &&
uqtype != ZFS_PROP_GROUPQUOTA) {
uqtype != ZFS_PROP_GROUPQUOTA &&
uqtype != ZFS_PROP_USERDNQUOTA &&
uqtype != ZFS_PROP_GROUPDNQUOTA) {
zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "'%s' is readonly"),
propname);
Expand Down Expand Up @@ -2649,8 +2651,12 @@ userquota_propname_decode(const char *propname, boolean_t zoned,
return (EINVAL);
*typep = type;

isuser = (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_USERUSED);
isgroup = (type == ZFS_PROP_GROUPQUOTA || type == ZFS_PROP_GROUPUSED);
isuser = (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_USERUSED ||
type == ZFS_PROP_USERDNQUOTA ||
type == ZFS_PROP_USERDNUSED);
isgroup = (type == ZFS_PROP_GROUPQUOTA || type == ZFS_PROP_GROUPUSED ||
type == ZFS_PROP_GROUPDNQUOTA ||
type == ZFS_PROP_GROUPDNUSED);

cp = strchr(propname, '@') + 1;

Expand Down Expand Up @@ -2783,7 +2789,8 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
(void) snprintf(propbuf, proplen, "%llu",
(u_longlong_t)propvalue);
} else if (propvalue == 0 &&
(type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
(type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA ||
type == ZFS_PROP_USERDNQUOTA || type == ZFS_PROP_GROUPDNQUOTA)) {
(void) strlcpy(propbuf, "none", proplen);
} else {
zfs_nicenum(propvalue, propbuf, proplen);
Expand Down
4 changes: 4 additions & 0 deletions module/zcommon/zfs_deleg.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ zfs_deleg_perm_tab_t zfs_deleg_perm_tab[] = {
{ZFS_DELEG_PERM_GROUPQUOTA},
{ZFS_DELEG_PERM_USERUSED},
{ZFS_DELEG_PERM_GROUPUSED},
{ZFS_DELEG_PERM_USERDNQUOTA},
{ZFS_DELEG_PERM_GROUPDNQUOTA},
{ZFS_DELEG_PERM_USERDNUSED},
{ZFS_DELEG_PERM_GROUPDNUSED},
{ZFS_DELEG_PERM_HOLD},
{ZFS_DELEG_PERM_RELEASE},
{NULL}
Expand Down
9 changes: 7 additions & 2 deletions module/zcommon/zfs_prop.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ const char *zfs_userquota_prop_prefixes[] = {
"userused@",
"userquota@",
"groupused@",
"groupquota@"
"groupquota@",
"userdnused@",
"userdnquota@",
"groupdnused@",
"groupdnquota@"
};

zprop_desc_t *
Expand Down Expand Up @@ -165,6 +169,7 @@ zfs_prop_init(void)
{ "3", 3 },
{ "4", 4 },
{ "5", 5 },
{ "6", 6 },
{ "current", ZPL_VERSION },
{ NULL }
};
Expand Down Expand Up @@ -301,7 +306,7 @@ zfs_prop_init(void)
/* default index properties */
zprop_register_index(ZFS_PROP_VERSION, "version", 0, PROP_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
"1 | 2 | 3 | 4 | 5 | current", "VERSION", version_table);
"1 | 2 | 3 | 4 | 5 | 6 | current", "VERSION", version_table);
zprop_register_index(ZFS_PROP_CANMOUNT, "canmount", ZFS_CANMOUNT_ON,
PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, "on | off | noauto",
"CANMOUNT", canmount_table);
Expand Down
Loading

0 comments on commit 29e8c12

Please sign in to comment.