STORAGE ENGINEERING

Linux filesystem quotas

Category: Storage AllocationTechnologies: ext4 quotas, XFS xfs_quota, Btrfs qgroups, ZFS quotas, project quotas

Filesystem quotas limit disk space and inode usage per user, group, or directory tree. They prevent any single user or application from consuming all available storage and are essential for multi-user systems, shared hosting, and capacity planning.

Quota types

TypeScopeUse case
User quotasAll files owned by a specific user (UID)Multi-user systems, per-user limits
Group quotasAll files owned by members of a group (GID)Project teams, departmental limits
Project quotasAll files within a directory tree, regardless of ownerPer-tenant limits in shared hosting, application directories

Soft vs hard limits

LimitBehavior
Soft limitCan be exceeded for a grace period. When grace expires, enforced as hard limit.
Hard limitAbsolute limit; cannot be exceeded (except with CAP_SYS_RESOURCE).
Grace periodTime allowed to exceed soft limit before enforcement. Default: 7 days. Per-filesystem and per-resource (blocks vs inodes).

ext2/3/4 quotas

Mount options

# Enable quotas at mount
mount -o usrquota,grpquota,prjquota /dev/sda1 /mnt

# /etc/fstab
/dev/sda1  /mnt  ext4  defaults,usrquota,grpquota  0 0

Modern ext4 quota feature (kernel 4.x+)

# Create ext4 with quota feature
mkfs.ext4 -O quota -E quotatype=usrquota:grpquota:prjquota /dev/sda1

# Enable on existing filesystem
tune2fs -Q usrquota,grpquota,prjquota /dev/sda1

Quota files

ext4 stores quota information in files at the filesystem root: aquota.user, aquota.group, aquota.project (v2 format, current). The older v1 format used quota.user, quota.group.

Workflow

# 1. Mount with quota options
mount -o usrquota,grpquota /dev/sda1 /mnt

# 2. Create/check quota files
quotacheck -cug /mnt

# 3. Enable quotas
quotaon -vug /mnt

# 4. Set quotas
setquota username 500000 550000 0 0 /mnt
# (block-soft block-hard inode-soft inode-hard, blocks in 1KB units)

# 5. Report
repquota -u /mnt

# 6. Disable
quotaoff -vug /mnt

XFS quotas

XFS stores quota information in filesystem metadata (no separate quota files), providing better performance. Quotas have two components: accounting (enabled at mount) and enforcement (can be toggled with xfs_quota).

Mount options

# User quota with enforcement
mount -o uquota /dev/sda1 /mnt
# or: mount -o usrquota /dev/sda1 /mnt

# Group quota
mount -o gquota /dev/sda1 /mnt

# Project quota
mount -o pquota /dev/sda1 /mnt

# Accounting only (no enforcement)
mount -o uqnoenforce /dev/sda1 /mnt

xfs_quota commands

# Report quotas (human-readable)
xfs_quota -c 'report -h' /mnt

# Report user/group/project quotas
xfs_quota -c 'report -u' /mnt
xfs_quota -c 'report -g' /mnt
xfs_quota -c 'report -p' /mnt

# Show quota state
xfs_quota -c 'state' /mnt

# Enable enforcement (expert mode required)
xfs_quota -x -c 'enable -u' /mnt
xfs_quota -x -c 'enable -g' /mnt
xfs_quota -x -c 'enable -p' /mnt

# Disable enforcement (accounting remains active)
xfs_quota -x -c 'disable' /mnt

# Set limits (expert mode)
xfs_quota -x -c 'limit bsoft=500m bhard=550m username' /mnt
xfs_quota -x -c 'limit isoft=10000 ihard=12000 username' /mnt
xfs_quota -x -c 'limit -g bsoft=10g bhard=12g groupname' /mnt
xfs_quota -x -c 'limit -p bsoft=20g bhard=25g projectname' /mnt

# Set default limits for new users
xfs_quota -x -c 'limit -d bsoft=500m bhard=550m' /mnt

Btrfs qgroups

Btrfs uses qgroups (quota groups) for subvolume-level quotas. Each subvolume automatically gets a qgroup with ID 0/<subvolumeID>. Higher-level qgroups (1/ID, 2/ID, etc.) can group subvolumes together.

Btrfs qgroup performance

Qgroups add significant overhead to all extent processing. Only enable if needed. Consider simple quotas (-s) for reduced overhead.

Enable and manage

# Enable quotas
btrfs quota enable /mnt

# Enable with simple quotas (less overhead, accounts to first owner)
btrfs quota enable -s /mnt

# Disable
btrfs quota disable /mnt

# Rescan quota metadata
btrfs quota rescan /mnt
btrfs quota rescan -w /mnt   # wait for completion
btrfs quota status /mnt

Qgroup management

# Show qgroups
btrfs qgroup show /mnt
btrfs qgroup show -r /mnt   # show referenced
btrfs qgroup show -e /mnt   # show exclusive

# Create qgroup
btrfs qgroup create 1/100 /mnt

# Assign subvolume to qgroup
btrfs qgroup assign 0/261 1/100 /mnt

# Set limits
btrfs qgroup limit 10G 1/100 /mnt
btrfs qgroup limit -e 5G 1/100 /mnt   # exclusive limit
btrfs qgroup limit -r 15G 1/100 /mnt  # referenced limit
btrfs qgroup limit none 1/100 /mnt    # remove limit

# Remove qgroup
btrfs qgroup remove 0/261 1/100 /mnt
btrfs qgroup destroy 1/100 /mnt

Referenced vs exclusive limits

TypeMeaning
Referenced (rfer)Total space reachable from any subvolume in the qgroup (includes shared data from snapshots/reflinks/dedup)
Exclusive (excl)Space unique to this qgroup (would be freed if all subvolumes in qgroup were deleted)

ZFS quotas

ZFS provides dataset-level, user/group/project-level, and reference quotas. All are set via ZFS properties, no separate quota files or mount options.

Dataset quotas

# Set quota (includes descendants and snapshots)
zfs set quota=100G pool/home/alice

# Set refquota (dataset's own referenced space only)
zfs set refquota=80G pool/home/alice

# View
zfs get quota,refquota,used,referenced pool/home/alice

# Remove
zfs set quota=none pool/home/alice

quota vs refquota

PropertyCountsUse case
quotaDataset + all descendants (including snapshots)Bound total space including snapshots
refquotaDataset's own referenced space onlyUser-visible limit (snapshots don't count against user)

User/group/project quotas

# User quota within a dataset
zfs set userquota@alice=10G pool/home
zfs set userquota@bob=15G pool/home

# Group quota
zfs set groupquota@staff=200G pool/home

# Project quota
zfs set projectquota@42=50G pool/data

# Default quotas (fallback for users without specific quota)
zfs set defaultuserquota=5G pool/home
zfs set defaultgroupquota=100G pool/home

# Object quotas (limit number of objects instead of bytes)
zfs set userobjquota@alice=100000 pool/home

# View user space usage
zfs userspace pool/home
zfs groupspace pool/home

Project quotas (directory quotas)

Project quotas provide directory-based quota limits independent of file ownership. They allow administrators to limit disk usage for specific directory trees regardless of which users own the files within them.

XFS project quotas

# 1. Add project to /etc/projects (ID:directory)
echo "100:/project/data" >> /etc/projects

# 2. Add project name to /etc/projid (name:ID)
echo "myproject:100" >> /etc/projid

# 3. Initialize the project directory
xfs_quota -x -c 'project -s myproject' /project/data

# 4. Set quota limits
xfs_quota -x -c 'limit -p bhard=10g myproject' /project/data

# Set project ID directly
xfs_io -c 'chproj 100' /project/data
xfs_io -c 'chproj -R 100' /project/data  # recursive

# Set project inheritance (new files inherit project ID)
chattr +P /project/data
chattr +P -R /project/data  # recursive

ext4 project quotas

# Set project ID
chattr -p 100 /project/data
chattr -p -R 100 /project/data  # recursive

# View project ID
lsattr -p /project/data

# Set project inheritance
chattr +P /project/data

Command reference

edquota (interactive)

# Edit user quota (opens $EDITOR)
edquota username

# Edit group quota
edquota -g groupname

# Edit project quota
edquota -P projectname

# Edit grace periods globally
edquota -t

# Edit grace period for specific user
edquota -T username

# Copy quota from prototype user
edquota -p prototype_user new_user

setquota (scriptable)

# Set user quota (blocks in 1KB units)
setquota username 500000 550000 50000 60000 /mnt

# Set group quota
setquota -g groupname 1000000 1100000 0 0 /mnt

# Set project quota
setquota -P projectname 2000000 2200000 0 0 /mnt

# Set grace period (seconds)
setquota -t 604800 604800 /mnt

# Copy from prototype
setquota -p prototype_user new_user /mnt

# Batch mode (read from stdin)
setquota -b /mnt < quotafile.txt

repquota (reporting)

# Report user quotas
repquota -u /mnt

# Report group quotas
repquota -g /mnt

# Report project quotas
repquota -P /mnt

# All filesystems, human-readable
repquota -a -s

# Don't resolve names (faster)
repquota -n /mnt

quota (user's own usage)

# Show user's own quotas
quota

# Group quotas
quota -g

# Project quotas
quota -P

# Verbose (show filesystems with no storage)
quota -v

# Human-readable
quota -s

warnquota (email alerts)

# Send email to users over quota
warnquota

# Check specific filesystems
warnquota /home /var

# Group quotas
warnquota -g

NFS quotas

NFS quota reporting uses rpc.rquotad on the server. The client quota command automatically queries the server via RPC.

# Start rpc.rquotad on server
systemctl enable --now rpc-rquotad

# /etc/hosts.allow (restrict access)
rquotad: 192.168.1.0/24

# /etc/hosts.deny
rquotad: ALL
NFS quota limitations

The rquota protocol only supports user quotas over NFS in most implementations. Group quotas may not be reported. Quota enforcement happens on the server, not the client.

Performance implications

FilesystemImplementationPerformance impact
ext4Separate quota files, journaledSome overhead on high-throughput workloads due to journal writes; benchmark before enabling
XFSMetadata-based (no separate files)Lower overhead than ext4; accounting always on, enforcement can be toggled
BtrfsExtent reference countingSignificant overhead; only enable if needed. Simple quotas (-s) reduce impact.
ZFSProperty-basedAsynchronous enforcement (small overage possible). Low overhead.

Best practices

  1. Use XFS for high-performance quota requirements. Metadata-based quotas have lower overhead than ext4's separate quota files.
  2. Set soft limit at 80-90% of hard limit to provide a warning buffer.
  3. Use grace periods: 7 days is standard; shorter for strict limits, longer for development environments.
  4. Use project quotas for shared hosting: directory-based limits independent of ownership.
  5. Use refquota on ZFS for user-visible limits, so snapshots don't count against the user.
  6. Only enable Btrfs qgroups if needed. They carry significant performance overhead.
  7. Monitor with repquota and schedule regular reports with trend analysis.
  8. Use warnquota to alert users before they hit hard limits.
  9. Test before production: validate quota configuration in a test environment first.
  10. Document quota policies and communicate limits clearly to users.