Cover V11, I09

Article

sep2002.tar

mquota -- A Passive Disk Quota System

Michael Montero

** missed drop char **quota was developed at Community Connect Inc. in November 2000. We needed a quota system under reiserFS 3.5.26 (running Linux kernel 2.2.16), and reiserFS itself did not support such a facility. Furthermore, we had special requirements for our quota system because most of our users would be accessing files using Samba and atalk rather than logging directly into a Linux server.

Quota systems are essential management tools when preserving disk space is a concern and when resources are shared among many users. For example, Internet Service Providers (ISPs) have long relied on quota systems to manage user accounts. Quota systems essentially allocate a fixed amount of disk space for a particular user (or group) and ensure that the amount of data saved never exceeds the allotted amount. Under Linux, the built-in Quota system (http://www.linuxdoc.org/HOWTO/Quota.html) is an effective method for implementing such policies.

Linux's Quota allows an administrator to set up a total number of inodes or disk blocks for a user or group of users to utilize. Attempts to save data when the quota limit is reached or exceeded will fail, thus prompting the user to make space for new data by deleting or moving files. Quota supports soft limits (the user is issued warnings about space consumption), hard limits (the user is no longer allowed to write to disk), and grace periods (an amount of time during which the soft limit will not be enforced). Quota has been incorporated in the Linux kernel since 1.3.8x and is now standard for the 2.0 kernel. A quota facility is available for ext2, ext3, and reiserFS (http://www.namesys.com/).

How mquota Works

mquota (http://www.bsdpro.com/scripts.php) works by summing up disk utilization at various times throughout the day (through cron) and taking action based on a user's or group's consumption. mquota is therefore a passive quota system because it will not immediately impede a user's ability to write data. (This is in contrast to an active quota system like Quota that can be configured to prevent a user or group from writing data as soon as the quota is reached or exceeded.)

Since users may not be logged into the server running mquota, we devised two methods for informing users of their disk consumption and availability. The first method incorporates sending email messages to a user when they are 75% or 90% of their quota. This message is used as a warning to notify the user of the available disk space. The second method involves writing a YOUR_QUOTA file in every directory being managed by mquota. The YOUR_QUOTA file contains the directory being monitored, the total disk space used, the total quota, and the percent used.

In addition to the report sent to a user or a group, centralized reports are created so an administrator can quickly observe disk utilization. Each time quotas are calculated, mquota writes out two files:

/var/log/mquota/mquota_dept.report
/var/log/mquota/mquota_user.report
To clarify the use of the term "dept", we aligned our Linux groups (in /etc/group) with our functional business units or departments. To keep the terminology consistent, we prefer the use of "dept" instead of "group". The report files contain the directory being monitored, the total disk space consumed, the total quota, and the percent used. We have used these reports in the past to determine whether disk space was becoming tight or whether we were too strict or too lenient with quota sizes.

At the heart of mquota is the Linux command:

/usr/bin/du
du is used to estimate file-space usage. When passed the -b option, du summarizes its output in bytes. Specifying -c will produce a grand total. An example execution of du is:

/usr/bin/du -bc /some/user/or/group/directory
The output appears like this (in this case, we ran it against /tmp):

4069            /tmp/directory1
8192            /tmp/directory2
40960           /tmp
40960           total
Two other options to use with du are -s to create a summary, and -h to put the results in "human-readable" form. The output of:

/usr/bin/du -bcsh /tmp
Looks like this:

40k             /tmp
40k             total
Note that mquota only uses the -b, -c, and -s options.

To put it all together, I'll start by listing all of the files and scripts we use and describe each.

Configuration

/etc/mquota/mquota.dept -- Contains information on department directories to monitor, their total quota in megabytes, and the contact person for notification emails.

/etc/mquota/mquota.user -- Contains a user name, the path to his home directory, and his total quota in megabytes.

Libraries

mquota.pl -- Perl library containing global variables and subroutines.

Scripts

adddeptmquota -- An administrative script for adding a new dept quota to the configuration file.

addusermquota -- An administrative script for adding a new user quota to the configuration file.

checkdeptquota -- cron that sums up the disk space used by the depts and takes action based on configuration file.

checkuserquota -- cron that sums up the disk space used by the users and takes action based on configuration file.

resetdeptdir -- Used to give write permission back to a dept directory after it has been disabled by mquota.

resetuserdir -- Used to give write permission back to a user directory after is has been disabled by mquota.

(Several of the other supporting scripts written were omitted because of their complexity or because they were solutions to problems for which we had very specific requirements.)

Before discussing the configuration files, it is worth mentioning that all of the scripts are "intelligent". For instance, they will not allow you to add a user if the user does not have an UNIX-level account, or if the user already has an mquota. In the latter instance, the user will not be added twice.

Both configuration files are in plain text and can be easily modified manually. The header for these files read:

#  mquota.dept
#
#  This file is used to manage the quotas for specific departments.
#  To add or remove values to this file, either manually add an entry
#  or use the administrative scripts located in /usr/local/cci/mquota.
#  The format for this file is:
#
#  [department]\t[directory]\t[quota in megabytes]\t[contact user name]\n
#

#  mquota.user
#
#  This file is used to manage the quotas for specific users.  To add or
#  remove values to this files, either manually add an entry or use the
#  administrative scripts located in /usr/local/cci/mquota.  The format
#  for this file is:

#
#  [user name]\t[directory]\t[quota in megabytes]\n
#
You might be wondering how we send email messages without email addresses. The user names on our servers are unified with user names throughout our system. Therefore, my user name would be mmontero and appending @mail.communityconnect.com would create my email address. mquota is designed to do just this.

At the heart of the system are checkdeptquota and checkuserquota, both of which are set to run out of cron. We have chosen to check quotas hourly (and conveyed the significance of this to our users) but could modify how often user and group directories are affected by increasing the frequency with which these two scripts execute. In this way, the "activeness" of mquota can be specified. Our cron entries look like this:

############################################################
#
#  Crons for mquota disk quota system.
#
#  Michael Montero        Nov 29, 2000
#
#
#  Check department drives for quota limits.
#
0 * * * * /usr/local/cci/mquota/checkdeptquota >
/var/log/mquota/checkdeptquota.log 2>&1

#
#  Check user drives for quota limits.
#

0 * * * * /usr/local/cci/mquota/checkuserquota >
/var/log/mquota/checkuserquota.log 2>&1

############################################################
Since these two scripts produce output about what they are doing, we redirect the output to log files so we can examine them if things need investigation. Note that the output from these is not the reports we generate for an administrator. One of the functions these scripts perform is writing the report directly to a predetermined report file.

checkdeptquota and checkuserquota perform several tasks during each execution. The first is to open the configuration file specified in mquota.pl defined in either $_MQUOTA_DEPT_FILE or $_MQUOTA_USER_FILE. The report file specified in mquota.pl defined in either $_MQUOTA_DEPT_REPORT or $_MQUOTA_USER_REPORT is then opened for writing. Each line of the configuration is then read and parsed. If any data are missing for an entry, the script immediately recognizes an error and aborts. If all data are provided, the du command is executed:

$command = "$_DU $deptDir |" ;
if ( !open( COMMAND, $command ) )
{
print "$0::main() -> fatal, cannot execute command $command.  Aborted.\n" ;
exit -1 ;
}

$junk  = <COMMAND> ;
$total = <COMMAND> ;
close( COMMAND ) ;
($_DU is defined in mquota.pl as /usr/bin/du -sbc.) The -s option produces two lines of output: the first is the total disk usage and the name of the directory passed to du, and the second is the total disk usage and the word "total". We discard the first line (assigning it to a variable called $junk) and assign the total to $total. We parse the $total variable to extract only the amount of disk space used. Because we can be dealing with disk spaces in several hundred megabytes and larger, we use the Math::BigInt and Math::BigFloat libraries of Perl. Various mathematical operations are done on these numbers, and these libraries provide subroutines for doing so.

Next, the disk space being used by either the user or group is compared against the allotted value specified in the configuration file. We determine the percentage of disk space used to see whether it is between $_MQUOTA_PERCENT_WARN and $_MQUOTA_PERCENT_FATAL, over $_MQUOTA_PERCENT_FATAL, but not quota or over quota. $_MQUOTA_PERCENT_WARN is currently defined as 75%, and $_MQUOTA_PERCENT_FATAL as 90%. If any of these thresholds are reached, email messages are sent to the user name extracted from the configuration file. If the user or group is over quota, their directory permissions for writing are revoked using this subroutine:

sub mquota_overquota
{
    my $dir = $_[ 0 ] ;             # the directory to disable

    $command = "( cd $dir ; $_MQUOTA_FIND_COMMAND . -type d -exec /bin/chmod 2550 {} \\; )" ;
    system( $command ) ;
    chmod( $_MQUOTA_DIR_OVER_PERMS, $dir ) ;
}

$_MQUOTA_FIND_COMMAND is defined as /usr/bin/find and
$_MQUOTA_DIR_OVER_PERMS as 02550 in mquota.pl.
After these checks have been performed, the YOUR_QUOTA file is written to the directory extracted from the configuration file. printf() is used to provide clean output:

printf YOURQUOTA "%-45s %12s %12s %7s\r\n",
"Directory", "Total Used", "Quota", "% Used" ;
printf YOURQUOTA "%-45s %12s %12s %7s\r\n\r\n",
"-----------", "-------------", "--------", "---------" ;
printf YOURQUOTA "%-45s %12s %12s %7s\r\n",
$directory, $total, $total_quota, $percent ;
The file generated by the code above is readable under Windows, Mac, or Linux and appears the same in all text file readers (that we've tested and are accustomed to using). Using almost identical code, a line is added to the summarization report generated.

The YOUR_QUOTA file for my home directory looks like this:

Directory                           Total Used        Quota  % Used
---------                           ----------        -----  ------
/mnt/raid/RAID00_5/people/mmontero  +407769088   +524288000  77.77%
The summarization report for depts looks like this (I provide only a snippet below):

Directory                               Total Used        Quota  % Used
---------                               ----------        -----  ------
/mnt/raid/RAID00_5/depts/cci           +4238495744  +5242880000  80.84%
/mnt/raid/RAID00_5/depts/mgmt              +463360   +104857600  .4418%
/mnt/raid/RAID00_5/depts/bizdev              +4608   +262144000  .0017%
/mnt/raid/RAID00_5/depts/mservices      +129280512   +262144000  49.31%
/mnt/raid/RAID00_5/depts/hr             +129034752   +524288000  24.61%
/mnt/raid/RAID00_5/depts/admins              +4608    +52428800  .0087%
/mnt/raid/RAID00_5/depts/pdt             +69592576  +1048576000  6.636%
/mnt/raid/RAID00_5/depts/aa             +229409792  +8912896000  2.573%
/mnt/raid/RAID00_5/depts/bp              +52784640  +8912896000  .5922%
/mnt/raid/RAID00_5/depts/mg             +328064000  +8912896000  3.680%
/mnt/raid/RAID00_5/depts/pr             +251612160   +524288000  47.99%
/mnt/raid/RAID00_5/depts/engineering      +4463104  +2621440000  .1702%
/mnt/raid/RAID00_5/depts/sa                 +46080 +10485760000  .0004%
There are some disadvantages to mquota. We have gotten around many of them because of how we have structured our servers, permissions, groups, and users. But shortcomings are still worth discussing.

The first obvious shortcoming is how "write permission" is turned off. Merely changing the permissions on the users' or groups' directories isn't always effective. It is still possible for a user to change the permissions back. We were able to circumvent this issue because most of the users of our systems do not have command-line access. Our users are typically reading and writing files through either Samba or atalk. A better enhancement to this would be to chown all of the directories and files to root, thus completely prohibiting users from their data.

Since we scheduled the crons to run every hour, it is possible for a single user to consume all of the disk space available. As long as they've filled up the disks before the cron runs, they will effectively use all the resources available. One obvious solution to this is to run the check scripts more frequently. A better solution, though, is to actively monitor the amount of data written and removed from disk.

Once a user has exceeded his quota, he is unable to continue to write or remove data until he has seen an administrator to reset his directory. A better implementation of a quota system would allow files to be removed (thus bringing oneself under quota) but not written. This was not essential to us because it gave us the ability to monitor our users' habits and educate them on the significance of file management (which we felt was far more important then not exceeding a quota). Typically, we have had issues where a particular user will require our intervention two or three times before our lecture becomes boring. Thereafter, they choose to more effectively manage their files.

We now install mquota on all of our servers regardless of the file system. mquota gives us quota control regardless of what operating system users currently use, will use in the future, or how they access their data. It has allowed us centralized management of our quota system -- we decide the standards for quotas and enforce them across multiple servers by synchronizing configuration files from a central server (with the rsync facility). mquota has allowed us to educate our users on the significance of data management and to enforce the behavior. So far, we have not had to purchase more storage space, which allows us to project our costs for data storage and back up and stay within our projections. Furthermore, configuring mquota is very simple (two plain-text configuration files) and is written entirely in Perl. Because most administrators know Perl (or find that it's easy to learn), it is easy to debug or expand mquota as our needs arise. It relies on proven UNIX commands like du and find, so we understand exactly what we are getting. Additionally, these commands are available on any flavor of UNIX (with varying output from each command).

mquota filled a specific need for our organization and grew into a significant tool for managing our systems. If there were one piece of advice I could impart about the experience, I would recommend implementing a quota system before users get into the habit of having "unlimited" disk capacity. In the end, the people maintaining the servers and the users who learn to manage their data will thank you.

Michael Montero is the Chief Technology Officer and a co-founder of Community Connect Inc., the leading publisher of online ethnic communities. He has been administering UNIX machines for more than eight years. Michael manages a brilliant staff of 20 helping to build and manage AsianAvenue.com, BlackPlanet.com, and MiGente.com. He can be contacted at: mmontero@mail.communityconnect.com.