Skip to content

Add hierarchical project quota support #17341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

jsai20
Copy link
Contributor

@jsai20 jsai20 commented May 16, 2025

ZFS has a project quota concept, where project is defined with unique id in dataset, called as project id (aka projid) and files/dirs inside dataset are assigned to project by setting projid on them.

By associating a project (projid) with specific directory tree in dataset and setting quota on the projid enforces a directory quota.

When needs to enforce different quota's in directory hierarchy, say want to limit usage of /d1/d2 to 10G and /d1/d3 also to 10G, this can be achieved by associating different project with /d1/d2 and /d1/d3 and setting quota on them. Now if want to limit the overall usage of /d1 to 15G. So need to associate another project with /d1, which should account the all usage under it. This would enforce a hierarchical directory quota.

So, to provide hierarchical directory quota, need of supporting multiple project in same hierarchy, where objects under child project are accounted in all projects in hierarchy upword. Project quota associated to directory should be enforced on usage of all of the object inside it regardless of either it has child quota in hierarchy or not. This means, if you have projet quota P1 (projid=11) associated to directory /d1 and child project quota P2 (projid=22) associated to /d1/d2, then usage of objects (files/dirs/..) under /d1/d2 would be accounted in both projid=11 and projid=22. Objects specific to /d1 would be accounted in projid=11.

To account object under child projects in all project in hierarchy up, each project needs to associated to immediate parent project. To discover a immediate parent project in hierarchy, project needs to be associated to root/top inode of project tree.
When associating a project to root/top inode of directory tree, parent project is found by walking up-word in hierarchy from the inode. Parent project is found, when it finds a parent inode, on which project id is set and this project id has inode association. Project to top/root inode and parent project association is maintained in the new ZAP object on disk.

Once a new project gets associated with its parent project, also correct the parent project of all existing projects. There could be a change in the parent project due to the new project quota. E.g. first associates a project 11 with /d1, so its parent project is none. Then associates a project 22 with /d1/d2/d3, so the project of /d1 becomes the parent of the project associated with /d1/d2/d3. Means, project 11 becomes the parent project of project 22. And finally associate a project 33 with /d1/d2, so now 11 becomes the parent project of 33 and 33 becomes the parent project of 22.

When associating a project to its new parent project (change in parent project), propagate current usage of project to its new parent project. Once a hierarchical relationship is established between projects, any further changes/writes on objects would account usage in objects project id as well as in its hierarchical parent project ids. To account existing objects usage under a new project, set project id on directory recursive. While Setting project id on objects under a project hierarchy, set the project id on objects if current project id is 0 or it has a project id where new project id being set is not the hierarchical parent of current project id on object. If project id being set is the hierarchical parent of current project id on the object, then usage of the object is already account-ed in project id being set via hierarchical association.

E.g. First associated project-id 22 with /d1/d2/d3, So, all objects inside /d1/d2/d3 are set with project id 22 and their usage gets account-ed in project 22. Now, when associating a new project 11 with /d1, project 11 would become a parent project of project 22 and as part of this association, current usage of project 22 would be propagated to project 11. After this, setting project id 11 on /d1 recursive would set project id 11 on all objects until it reaches the /d1/d2/d3 which has a project id 22 and it would break here as project id 11 being set is parent project of 22. This effectively would account for the remain-ing project 11 specific objects usage in it.

In another case, where the project 11 first associated with /d1 and so usage of all objects under /d1 gets account-ed under project 11. Now, later associate project 22 with /d1/d2/d3, so the usage of objects within /d1/d2/d3 would be account-ed in project id 22, while setting project id 22 on /d1/d2/d3 and underneath objects. As project 11 is already associated as parent project of 22, so by setting project id 22 on objects from earlier project id 11, it would account the objects usage in project 22. For project 11, usage would decrement with respect to changing id from 11 to 22 and increment back with respect to 11 is hierarchical parent of 22, so effectively no change/delta in usage of project 11 would happen as expected.

Projects once associated in the hierarchy, its association won’t be removed until it has an active parent project (quota is set) associated. Association is needed for hierarchical accounting purposes. Projects without active parent projects in hierarchy would be dis-associated from hierarchy. So, when a project is removed (quota is set to none), ZFS would disassociate non-active projects (quota none), which don't have parent projects.

Hierarchical quota is enforced by checking project quota on project of object as well as parent projects in hierarchy.

Motivation and Context

Description

How Has This Been Tested?

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv)
  • Documentation (a change to man pages or other documentation)

Checklist:

@behlendorf behlendorf added the Type: Feature Feature request or new feature label May 16, 2025
@jsai20 jsai20 force-pushed the project-hierarchical-quota branch from 42c7759 to 295c645 Compare May 17, 2025 06:38
ZFS has a project quota concept, where project is defined with
unique id in dataset, called as project id (aka projid) and files/dirs
inside dataset are assigned to project by setting projid on them.

By associating a project (projid) with specific directory tree in
dataset and setting quota on the projid enforces a directory quota.

When needs to enforce different quota's in directory hierarchy, say
want to limit usage of /d1/d2 to 10G and /d1/d3 also to 10G, this
can be achieved by associating different project with /d1/d2 and /d1/d3
and setting quota on them. Now if want to limit the overall usage of
/d1 to 15G. So need to associate another project with /d1, which should
account the all usage under it. This would enforce a hierarchical
directory quota.

So, to provide hierarchical directory quota, need of supporting multiple
project in same hierarchy, where objects under child project are
accounted in all projects in hierarchy upword. Project quota associated
to directory should be enforced on usage of all of the object inside it
regardless of either it has child quota in hierarchy or not. This means,
if you have projet quota P1 (projid=11) associated to directory /d1 and
child project quota P2 (projid=22) associated to /d1/d2, then usage of
objects (files/dirs/..) under /d1/d2 would be accounted in both
projid=11 and projid=22. Objects specific to /d1 would be accounted in
projid=11.

To account object under child projects in all project in hierarchy up,
each project needs to associated to immediate parent project. To
discover a immediate parent project in hierarchy, project needs to be
associated to root/top inode of project tree.
When associating a project to root/top inode of directory tree, parent
project is found by walking up-word in hierarchy from the inode. Parent
project is found, when it finds a parent inode, on which project id is
set and this project id has inode association. Project to top/root inode
and parent project association is maintained in the new ZAP object on
disk.

Once a new project gets associated with its parent project, also correct
the parent project of all existing projects. There could be a change in
the parent project due to the new project quota. E.g. first associates a
project 11 with /d1, so its parent project is none. Then associates a
project 22 with /d1/d2/d3, so the project of /d1 becomes the parent of
the project associated with /d1/d2/d3. Means, project 11 becomes the
parent project of project 22. And finally associate a project 33 with
/d1/d2, so now 11 becomes the parent project of 33 and 33 becomes the
parent project of 22.

When associating a project to its new parent project (change in parent
project), propagate current usage of project to its new parent project.
Once a hierarchical relationship is established between projects, any
further changes/writes on objects would account usage in objects project
id as well as in its hierarchical parent project ids. To account
existing objects usage under a new project, set project id on directory
recursive. While Setting project id on objects under a project
hierarchy, set the project id on objects if current project id is 0 or
it has a project id where new project id being set is not the
hierarchical parent of current project id on object. If project id being
set is the hierarchical parent of current project id on the object, then
usage of the object is already account-ed in project id being set via
hierarchical association.

E.g. First associated project-id 22 with /d1/d2/d3, So, all objects
inside /d1/d2/d3 are set with project id 22 and their usage gets
account-ed in project 22. Now, when associating a new project 11 with
/d1, project 11 would become a parent project of project 22 and as part
of this association, current usage of project 22 would be propagated to
project 11. After this, setting project id 11 on /d1 recursive would set
project id 11 on all objects until it reaches the /d1/d2/d3 which has a
project id 22 and it would break here as project id 11 being set is
parent project of 22. This effectively would account for the remain-ing
project 11 specific objects usage in it.

In another case, where the project 11 first associated with /d1 and so
usage of all objects under /d1 gets account-ed under project 11. Now,
later associate project 22 with /d1/d2/d3, so the usage of objects
within /d1/d2/d3 would be account-ed in project id 22, while setting
project id 22 on /d1/d2/d3 and underneath objects. As project 11 is
already associated as parent project of 22, so by setting project id 22
on objects from earlier project id 11, it would account the objects
usage in project 22. For project 11, usage would decrement with respect
to changing id from 11 to 22 and increment back with respect to 11 is
hierarchical parent of 22, so effectively no change/delta in usage of
project 11 would happen as expected.

Projects once associated in the hierarchy, its association won’t be
removed until it has an active parent project (quota is set) associated.
Association is needed for hierarchical accounting purposes. Projects
without active parent projects in hierarchy would be dis-associated from
hierarchy. So, when a project is removed (quota is set to none), ZFS
would disassociate non-active projects (quota none), which don't have
parent projects.

Hierarchical quota is enforced by checking project quota on project of
object as well as parent projects in hierarchy.

Signed-off-by: Jitendra Patidar <[email protected]>
@jsai20 jsai20 force-pushed the project-hierarchical-quota branch from 295c645 to 1ed2a49 Compare May 17, 2025 06:50
@snajpa
Copy link
Contributor

snajpa commented May 20, 2025

Two things, if I may:

  • have you considered adding a send/recv test to make sure the accounting survives replication correctly?
  • man pages seem untouched yet

@jsai20
Copy link
Contributor Author

jsai20 commented May 21, 2025

Two things, if I may:

  • have you considered adding a send/recv test to make sure the accounting survives replication correctly?
  • man pages seem untouched yet

Send/recv would need some handling to correct the accounting in project hierarchy.
Basically "PROJECT_HIERARCHY" zap, when received on target side (on temp clone from base snap), need to compare it with the "PROJECT_HIERARCHY" zap on base snapshot. And as per change in "PROJECT_HIERARCHY" correct the usage in project hierarchy. I am still working on send/recv part of it. I would update changes along with test case, once its ready.

zfs-project man page would need update. I would update it along with other changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature Feature request or new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants