UFS Disk Quotas on FreeBSD: Enable, Enforce, Audit, and Recover
Configure FreeBSD UFS user and group quotas with safe activation, hard and soft limits, inode controls, accounting checks, and recovery tests.
UFS disk quotas constrain how much filesystem space a user or group can allocate on a particular mounted UFS filesystem. They are useful on shared home, spool, or project filesystems where one identity should not consume all available blocks or inodes. Quotas are not a reservation, filesystem resize, backup, or guarantee that the filesystem itself will remain below capacity. A host can be out of free space even when every user is under quota.
FreeBSD’s UFS quota system combines kernel accounting, quota database files stored at the filesystem root, /etc/fstab mount options, startup configuration, and limits administered with edquota(8). Each piece must agree. A quota_enable setting alone does not turn quotas on for every filesystem, and an edquota limit alone cannot constrain allocations if the corresponding filesystem was not mounted with quota support.
This guide focuses on UFS quotas. ZFS implements a different model with dataset, reference, user, and group quota properties; do not apply UFS quota files or quota_enable assumptions to a ZFS dataset.
Confirm that the filesystem and kernel support quotas
Start with the target mount, its actual filesystem type, and the running kernel’s quota feature:
mount -p
sysctl kern.features.ufs_quota
grep -E '[[:space:]]/home[[:space:]]' /etc/fstab
freebsd-version -kru
The feature value 1 indicates that the running kernel provides UFS quota support. If it is 0, the Handbook documents options QUOTA for a custom kernel; that is a kernel build and rollout decision, not a runtime toggle. Do not attempt to enable a custom kernel option on a production system without matching source, a recovery kernel, and a tested boot path.
Confirm that the target is really UFS. UFS quotas use the userquota and groupquota mount options and quota.user and quota.group files at the filesystem root by default. ZFS datasets use ZFS properties instead. Network filesystems also have distinct quota semantics; NFS quota enforcement belongs to the server, while a client may query status through the remote quota service.
Choose a dedicated mount boundary deliberately. A quota applies to the UFS filesystem, not to an arbitrary subdirectory tree. If /home shares the root filesystem, quotas affect the entire UFS filesystem scope rather than just one user’s path. A separate /home filesystem makes both the capacity boundary and quota accounting easier to reason about, but creating or migrating filesystems is a storage change outside this quota procedure.
Plan block, inode, user, and group limits
UFS quotas can limit allocated blocks, file counts (inodes), or both, separately for each user and group. A user quota follows the numeric UID and a group quota follows the numeric GID. Renaming a login without changing its UID preserves ownership identity; reusing an old UID or GID can make a different account inherit existing usage and limits. Include identity mapping in account migration plans.
A hard limit cannot be exceeded for new allocation. A soft limit can be exceeded temporarily; once the configured grace period expires, further allocation is denied until usage falls below the soft limit. FreeBSD’s Handbook documents a one-week default grace period. Users may see EDQUOT from applications when a quota blocks writes even though df shows free blocks remaining. Conversely, ENOSPC can occur when the filesystem is full even if the caller’s quota has headroom.
Set a capacity policy before activating limits. Estimate normal and peak usage, growth rate, temporary files, inode churn, shared group ownership, and operational headroom. A block-only policy can leave a workload unable to create a small file after it exhausts inodes; an inode-only policy can leave it able to write a very large file. Choose both limits when both failure modes matter. Make the hard limit a final boundary, not the normal alert threshold.
Enable accounting at the filesystem boundary
For a filesystem mounted at /home, first preserve its current fstab entry and mount options. The following is a schematic row; replace the provider with the actual persistent device or label and retain any required local options:
# fs_spec fs_file vfstype fs_mntops fs_freq fs_passno
/dev/gpt/ufs-home /home ufs rw,userquota,groupquota 1 2
Add quota_enable="YES" to /etc/rc.conf using sysrc. Then enable userquota, groupquota, or both in the fstab options for each selected UFS filesystem. The default quota files are created at the root of that filesystem. The Handbook warns that alternate quota-file locations are not recommended.
sysrc quota_enable="YES"
sysrc quota_enable
On a planned reboot, /etc/rc processes the quota-enabled fstab entries and creates initial quota files as needed. Startup normally runs quotacheck(8) so database usage reflects files already present; on a very large filesystem this scan can lengthen boot. Do not disable that check solely to shorten boot time unless there is a tested alternative for keeping quota accounting consistent.
For an online activation, remember that editing /etc/fstab does not change options on an already-mounted filesystem. Verify the active mount options, then follow the installed release’s quotacheck(8) and quotaon(8) manuals for the required activation and scan sequence. quotacheck reads raw filesystem state and its manual requires the filesystem to be quiescent while it runs; drain writes or use the normal reboot/startup path instead of treating a low-write period as sufficient. Do not create or edit the binary quota files by hand. Once the filesystem is mounted with the quota options, the fstab-driven commands are:
quotacheck -v -a
quotaon -v -a
These commands act on the filesystems selected from /etc/fstab; quotaon changes enforcement state. Read both manual pages before running them, and inspect each result rather than assuming a zero-length or missing quota database means there is no existing usage. If there is uncertainty about mount flags or filesystem state, use the documented reboot initialization path or a controlled maintenance procedure instead of improvising a live quota-file repair.
Set and provision limits
edquota(8) opens an editor with the selected user’s current usage and limits for quota-enabled filesystems. Use -u for a user and -g for a group:
edquota -u buildbot
edquota -g engineering
The interactive table has a block line and an inode line for each applicable filesystem. On the block line, usage and limits are shown in kilobytes; the inode line counts files. Change the soft and hard fields only after checking the account’s real workload. A new account with zero usage may not appear in every default quota report, so use verbose queries when confirming an assigned policy.
For a repeatable cohort, establish and review a template quota first, then copy that policy to a deliberate UID or user range using the supported edquota -p operation. Do not assume that a numeric range is equivalent to a business team: confirm current account ownership and avoid including system service IDs. Group quota assignment is often more stable for shared project directories, but only if the files actually carry the intended group ownership.
Grace times are policy too. Inspect and set user or group grace periods through edquota -t or edquota -g -t, as appropriate. A grace period that is too short can turn a transient deployment burst into failed writes; one that is too long can allow chronic overuse. Alert before expiration, and make the remediation path clear to the user or service owner.
Verify limits with independent views
Use individual reports for the affected identity and a filesystem-wide report for the operator view:
quota -v -u buildbot
quota -v -g engineering
repquota -v -a
quota -v includes filesystems where the user has a limit but may not currently use space. repquota -a summarizes quota-enabled filesystems listed in fstab. Compare reported block and file use with the expected owner and test directory. If counts differ after a restore or UID/GID remapping, stop before increasing a limit to mask the discrepancy; investigate ownership and quota accounting first.
In staging, test each boundary with a disposable user and filesystem: remain below soft limits, cross a soft limit and confirm the displayed grace state, cross a hard limit and confirm the expected application error, then delete test data and verify recovery below soft. Repeat for inodes. Never fill a production filesystem to test quota enforcement. Use a dedicated disposable filesystem, set low test limits, and remove only the test files and identities afterward.
Also verify the failure path from the application. A program may treat EDQUOT as a fatal write error, retry forever, or surface a misleading generic “disk full” message. Monitor quota headroom for both blocks and files, filesystem free space, and quota-check or startup errors. A successful quota -v command is not an alerting system.
Restore accounting without hiding the underlying fault
The quota database is accounting state. If data is restored, ownership IDs are remapped, or the quota files may be inconsistent, quotacheck(8) scans actual usage and compares it to the quota database. Run it under a maintenance plan appropriate to the filesystem and workload; a large scan consumes I/O and can add operational load. Let FreeBSD’s documented startup path manage normal checks unless there is a specific reason to run a manual repair.
Keep quota files with the filesystem’s recovery records and ensure backups can restore both user data and ownership. After file-level restoration, raw filesystem recovery, or identity remapping, reconcile accounting and verify with repquota before declaring the quotas trustworthy. Do not edit quota.user or quota.group as text files: they are database files maintained through the kernel quota interface and quota tools.
Quotas are only one layer of capacity management. Pair them with filesystem-level monitoring, alerting on inode exhaustion, verified backup/restore, and a documented emergency procedure for raising a limit. On ZFS, define dataset boundaries and use the matching ZFS quota properties rather than carrying these UFS activation commands over. A production quota system is complete when the correct owner is charged, the soft and hard behavior is tested, the operator can see approaching limits, and accounting can be rebuilt safely.
Related:
- UFS Soft Updates and Journaling on FreeBSD: What Each Mechanism Protects
- ZFS on FreeBSD: Pools, Datasets, and Snapshots Explained
Sources: