jack@suse.cz
Quota subsystem allows system administrator to set limits on used space and number of used inodes (inode is a filesystem structure which is associated which each file or directory) for users and/or groups. For both used space and number of used inodes there are actually two limits. The first one is called softlimit and the second one hardlimit. An user can never exceed a hardlimit for any resource. When an user exceeds a softlimit (s)he is warned that (s)he uses more space than (s)he should but space/inode is allocated (of course only if an user also does not exceed the hardlimit). If an user is exceeding softlimit for specified period of time (this period is called grace time) (s)he is not allowed to allocate more resources (so (s)he must free some space/inodes to get under softlimit).
Quota limits are set independently for each filesystem. Currently following filesystems are supporting quota: Ext2, Ext3, ReiserFS, XFS.
In order for quota subsystem to work you have to have quota compiled in a kernel and configured appropriately. That means that the filesystem on which you want to use quotas must be mounted with quota options so that quota tools recognize the filesystems to work with (and also a filesystem itself might use the information). Currently there are following quota options (note that XFS uses completely different quota system and these information does not apply to it):
usrquota
or quota
or usrjquota=filename
if you want to use
limits for usersgrpquota
or grpjquota=filename
if you want to use limits for
groupsusrquota
and grpquota
options have also alternative with
=filename
appended. filename
is then used as a name (together with
path) of quota file to use. But note that by this you prevent quota utilities
to do some useful autodetection. jquota
mount options tell the tools and
also the filesystem that it should journal the quota. That basically means that
quota on disk is updated together with filesystem's metadata and hence you do
not need to run quotacheck(8)
after an unclean shutdown. For these options
specifying of filename is mandatory (because filesystem also needs to know the
file with quota information) and filename
must specify a file in the root
directory of a filesystem. When any of jquota
options is specified
additional option jqfmt=format
must be also specified where format
is
a format of quota files. As journaled quota is currently supported only for
vfsv0
format the value of format must be vfsv0
. Note also that
journaled quota is currently (as of March 2004) supported only for Ext3
filesystem and you need to have a kernel patched with a special patch
(contained for example in -mm series of a kernel).
For each filesystem with quotas you have to have files with quota data. The
name of these quota files depends on
quota format and you can even specify the filenames by yourself by adding
=filename
to usrquota
or grpquota
options -- e.g.
usrquota=file.quota
. But note that by this you prevent quota utilities to
do some useful autodetection. The quota files can be created by
quotacheck(8)
utility. When you have successfully created quota files you
can turn quotas on (ie. system will start tracking how much each user uses and
will check set limits). This is done by quotaon(8)
program.
When you already have working quota subsystem but you want to use newer quota format
you have to convert quota files. This can be done by convertquota(8)
utility.
You can edit user (group) limits by edquota(8)
or setquota(8)
programs.
By these programs you can also set grace times.
Original quota format was the only one available in kernels up to 2.4.21 Linux
kernels (note that vendors such as RedHat or SuSE have included quota
format patches into their kernels earlier and use
newer quota format). This quota format is in manpages and quota utils
called vfsold
.
Data for this format are usually stored in files quota.user
(for user quotas) and
quota.group
(for group quotas). Both files have the same structure. They are just
the arrays of following structures:
struct v1_disk_dqblk { u_int32_t dqb_bhardlimit; /* Absolute limit on disk blks alloc */ u_int32_t dqb_bsoftlimit; /* Preferred limit on disk blks */ u_int32_t dqb_curblocks; /* Current block count */ u_int32_t dqb_ihardlimit; /* Maximum # allocated inodes */ u_int32_t dqb_isoftlimit; /* Preferred limit on inodes */ u_int32_t dqb_curinodes; /* Current # allocated inodes */ time_t dqb_btime; /* Time limit for excessive disk use */ time_t dqb_itime; /* Time limit for excessive files */ };
N
is stored as N
-th structure in file.
In fields dqb_btime
and dqb_itime
of first structure (id = 0) are stored
grace times for this filesystem.
This quota format is currently available in 2.4.22 and newer kernels. Also
kernels distributed by RedHat (>= 7.1) and SuSE (>= 7.2) contain support for
this quota format. This format is called vfsv0
in manpages and utilities
and quota files are usually called aquota.user
and aquota.group
.
This quota format has following advantages against old quota format:
Format of quota file is the following: In the beginning of quota file there is a generic header which is intended to be present in every quota file in future. The header has the following structure:
struct disk_dqheader { __u32 dqh_magic; /* Magic number identifying file */ __u32 dqh_version; /* File version */ };
Following header might be specific for quota type and version (currently this header is the same for user and group quota and there is only one version of quota file format).
struct disk_dqinfo { __u32 dqi_bgrace; /* Time before block soft limit becomes hard limit - in seconds */ __u32 dqi_igrace; /* Time before inode soft limit becomes hard limit - in seconds */ __u32 dqi_flags; /* Flags for quota file (DQF_*) (currently there are no ondisk flags) */ __u32 dqi_blocks; /* Number of blocks in file */ __u32 dqi_free_blk; /* Number of first free block in the list */ __u32 dqi_free_entry; /* Number of block with at least one free entry */ };
dqi_free_blk
points to
the first element of this list). The second linked list is used to link all
data blocks which have at least one entry free and which also have at
least one used entry. The beginning of the list is pointed by
dqi_free_entry
.
The rest of a file (starting at 1KB) is divided into 1KB blocks. In these blocks is stored a radix tree with quotas. The key for the radix tree is UID or GID (I will use just ID in the following text) depending on a quota file type. One node of the tree is 1KB block so there are up to 256 references to the sons. At each level we choose reference corresponding to one byte of ID so having four-level radix tree we can support 32-bit IDs. Reference from the last level points to data block which contains quota structure for proper ID.
Data block has following structure: In the beginning there is a header with the following structure:
struct disk_dqdbheader { __u32 dqdh_next_free; /* Number of next block with free entry */ __u32 dqdh_prev_free; /* Number of previous block with free entry */ __u16 dqdh_entries; /* Number of valid entries in block */ __u16 dqdh_pad1; __u32 dqdh_pad2; };
dqdh_next_free
and dqdh_prev_free
are used only if the block
has at least one free and one used entry. If it has no free entry these
references are set to 0. When block is completely free only dqdh_next_free
is used for linked list of free blocks.
The rest of the block is divided into 21 quota entries. Unused entry is entry that contains only zeros. Note that used entries might be freely scattered in the block. Quota entry has the following structure:
struct disk_dqblk { __u32 dqb_id; /* id this quota applies to */ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ __u32 dqb_isoftlimit; /* preferred inode limit */ __u32 dqb_curinodes; /* current # allocated inodes */ __u32 dqb_bhardlimit; /* absolute limit on disk space (in kb) */ __u32 dqb_bsoftlimit; /* preferred limit on disk space (in kb) */ __u64 dqb_curspace; /* current space occupied (in bytes) */ __u64 dqb_btime; /* time limit for excessive disk use */ __u64 dqb_itime; /* time limit for excessive inode use */ };
As of version 3.01 quota utilities support original, vfsv0 and xfs quota format.
You can download latest version of utils from http://www.sf.net/projects/linuxquota/
.
Utils try to do autodetection of currently used quota format (i.e. they detect which
format is compiled into kernel and they try to use this one). Anytime you can
force utils to use different format by specifying -F <format>
. More information
about quota utils can be found in appropriate manpages.