Linux 磁盘 quota

Mike Chirico (mchirico@users.sourceforge.net) or (mchirico@comcast.net)
Copyright (c) 2005 (GNU Free Documentation License)
Last Updated: Sun Jan 15 08:23:29 EST 2006
[ http://souptonuts.sourceforge.net/quota_tutorial.html]

Implementing Disk Quotas on Linux

This tutorial walks you through implementing disk quotas for bothusers and groups on Linux, using a virtual filesystem, which is a filesystem created from a disk file. Since quotas work on a per-filesystem basis, this is a way to implement quotas on a sub-section, or even multiple subsections of your drive, without reformatting. This tutorial alsocovers quotactl, or quota's C interface, by way of an example program that can storedisk usage in a SQLite database for monitoring data usage over time.

This tutorial was tested on Fedora Core 2, 3, and 4. I'm assuming you have the quota tools installed. If you're not sure, try the following test, which willreturn 3.12-6 or 3.12-5 depending on which version of Fedora Core you areusing.

    $ rpm -q quota
    quota-3.12-6    

Creating a Virtual Filesystem

The following steps walk you through creating a ext3 virtual filesystem mounted on "/quota"with a size of 20 MB. Again, since quotas are installed on a filesystem, we're going to createan isolated filesystem.

The mount point for this filesystem will be "quota". As root, first create the mount point quota,which at this point is just a directory.

   # mkdir -p /quota

Next, create a 20M file (disk image) in a suitable location. What I did below is create the file disk-quota.ext3 in the directory /usr/disk-img.

   # mkdir -p /usr/disk-img
   # dd if=/dev/zero of=/usr/disk-img/disk-quota.ext3 count=40960

The dd command above created a 20MB file because, by default, dd uses a block size of512 bytes. That makes this size: 40960*512=20971520. For kicks, we'll confirmthis size.

   # ls -lh /usr/disk-img/disk-quota.ext3
   -rw-r--r--  1 root root 20M Jul 19 14:34 /usr/disk-img/disk-quota.ext3

Next, format this as an ext3 filesystem.

   # /sbin/mkfs -t ext3 -q /usr/disk-img/disk-quota.ext3 -F

The "-t" gives it the type. You're not limited to ext3. In fact, you could use ext2 orother filesystems installed on your system. The "-q" is for the device, and "-F" isto force the creation without warning us that this is a file and not a block device.

Add the following line to "/etc/fstab". This will make the filesystem always availableon reboot, plus it's easier to mount and unmout when testing.

    /usr/disk-img/disk-quota.ext3    /quota ext3    rw,loop,usrquota,grpquota  0 0

Now, mount this filesystem.

    # mount /quota

 Or if you didn't edit /etc/fstab above

    # mount -o loop,rw,usrquota,grpquota /usr/disk-img/disk-quota.ext3 /quota

Now take a look at /quota. You should see the "lost+found" directory. Plus, youcan take a look at /proc/mounts to see that you have an "ext3" type filesystem. At this point you can create and add files if you want.

    # ls
    lost+found

    # grep 'quota' /proc/mounts
    /dev/loop0 /quota ext3 rw 0 0 

The mount command below shows us usrquota and grpquota options have been added.

    # mount | grep '/quota' 
    /usr/disk-img/disk-quota.ext3 on /quota type ext3 (rw,loop=/dev/loop0,usrquota,grpquota)


Sharing a Directory amoung Several Users

This step creates a group and implements group rights on a directorywithin the quota filesystem. Specifically, this step creates the group,"quotagrp" and adds the two existing users "chirico" and "sporkey" into this group. The direcory "/quota/share" is setup so that any files createdin this directory by these two users will be sharable by default for membersof this group. This is done by setting the setgid bit on the directory.

First create the group and add any existing users.

   # groupadd quotagrp
   # usermod -G quotagrp chirico
   # usermod -G quotagrp sporkey

Create the directory /quota/share and set the access rights so that filescreated in this directory can be edited by any group members.

   # mkdir -p /quota/share
   # chown -R root.quotagrp /quota/share
   # chmod 2775 /quota/share

Above the command "2755" sets the "setgid" bit. You can see this with the"ls" command below.

   # ls -ld /quota/share
   drwxrwsr-x  2 root quotagrp 1024 Jul 19 15:16 /quota/share/
         ^---------- Note the s, setgid bit, from  chmod 2775

An important note here. If the users above "chirico" and "sporkey" are currentlylogged in when they were added to the group, they will not get access to the group.These users need to login again. Having these users run "newgrp" or even "newgrp -"(Fedora core 4) will give them access to the group; however, this will not correctlyset group file permissions. To avoid trouble in a production environment have userslogin again or execute "su - " to corrently initilize their environment.

  Execute from chirico account. 

   $ groups
   chirico

   $ su - chirico
   Password:

   $ groups   
   quotagrp chirico

Quotas

Run quotecheck. The first time you run this command, use the "-c" option to create thenecessary database files. The following should be run as root.

   # quotacheck -cug /quota

Note that two files have been created "aquota.group" and "aquota.user".

   # ls -l /quota
   aquota.group  aquota.user  lost+found  share

Use "edquota" to grant the user "chirico" the desired quota.

   # edquota -f /quota chirico

Executing the command above brings up a text file in your default editor. Youwill change entries in this file.

 Disk quotas for user chirico (uid 500):
  Filesystem                   blocks       soft       hard     inodes     soft     hard
  /dev/loop0                        0          0          0          0        0        0

Above for user chirico there have been no blocks or inodes used on this filesystem. Note thatan inode is used for each file and directory. We'll change the settings as follows:

 Disk quotas for user chirico (uid 500):
  Filesystem                   blocks       soft       hard     inodes     soft     hard
  /dev/loop0                        0        100        200          0       10       15

Note that the numbers under "blocks" and "inodes" indicated the current blocks and inodes inuse by this user. Those values should not be edited, since they are only used for reference.

setquota - command line quota editor

You can also use the setquota command, which has the advantage of not usingan editor making it ideal for implementing in a script. For example, to set the soft block limit to 100, a hard block limit of 200, a soft inodeto 10 and a hard inode to 15 as we did above, execute the following command.

   # setquota -u chirico 100 200 10 15  -a /dev/loop0

Turn quotas on with the following command.

  # quotaon /quota

From the root user you can "su" into the chirico account to see the changes.

  # su - chirico
  $ touch /quota/share/t1
  $ quota
  Disk quotas for user chirico (uid 500):
       Filesystem  blocks   quota   limit   grace   files   quota   limit   grace
       /dev/loop0       1     100     200               1      10      20

As an interesting test, still under this user, create a hard link as follows with theln command. Then execute the quota command to see how many inodes are taken.

  $ ln  /quota/share/t1 /quota/share/t2

  $ quota
  Disk quotas for user chirico (uid 500):
       Filesystem  blocks   quota   limit   grace   files   quota   limit   grace
       /dev/loop0       1     100     200               1      10      20

Note that the number of files has not changed. However, if you create a symbolic link, sometimes called a soft link, with the "ln -s" command, the number will increse to 2, becausean additional inode is created with a soft link.

  $ ln -s /quota/share/t1 /quota/share/t3

  $ quota
  Disk quotas for user chirico (uid 500):
       Filesystem  blocks   quota   limit   grace   files   quota   limit   grace
       /dev/loop0       2     100     200               2      10      20

Quotas for Groups

To set quotas for the group "quotagrp", use the following command.

   # edquota -g quotagrp
   Disk quotas for group quotagrp (gid 619):
     Filesystem                   blocks       soft       hard     inodes     soft     hard
     /dev/loop0                        6          0          0          4        0        0

Now make the following changes.

   Disk quotas for group quotagrp (gid 619):
     Filesystem                   blocks       soft       hard     inodes     soft     hard
     /dev/loop0                        6          5        100          4        6       10

Or, use the "setquota" command as follows:

   # setquota -g quotagrp 5 100 6 10 -a /dev/loop0

Now run the following command under the user account that has group access, which will attempt to create 15 files.

   $ for i in $(seq 15); do  touch "/quota/share/file_$i"; done
   loop0: warning, group file quota exceeded.
   loop0: write failed, group file limit reached.
   touch: cannot touch `/quota/share/file_7': Disk quota exceeded

Reports

The "repquota" command prints a summarized report. It should be runwith root.

   # repquota /quota
   *** Report for user quotas on device /dev/loop0
   Block grace time: 7days; Inode grace time: 7days
                           Block limits                File limits
   User            used    soft    hard  grace    used  soft  hard  grace
   ----------------------------------------------------------------------
   root      --    1204       0       0              5     0     0
   chirico   --      10     100     200              9    10    20

To get a report by group, use the -g option as follows.

   # repquota -g /quota
   *** Report for group quotas on device /dev/loop0
   Block grace time: 7days; Inode grace time: 7days
                           Block limits                File limits
   Group           used    soft    hard  grace    used  soft  hard  grace
   ----------------------------------------------------------------------
   root      --    1202       0       0              4     0     0
   quotagrp  ++      12       5     100  6days      10     6    10  6days

Note the "++" above for quotagrp indicating that both the block limit andinode limits have been exceeded.

Or to get everything, run repquota with the -a option as follows.

   # repquota -a

warnquota - send mail to users over quota

Running warnquota without any options will email users that go overthe limit.

   # warnquota

However in this case no mail message will be sent, because the group limitwas exceeded. The file "/etc/quotagrpadmins" needs to contain a usernameresponsible for the group. Here will put in the user "sporkey", so that thefile looks as follows:

   #
   # This is a sample groupadmins file (/etc/quotagrpadmins)
   #
   #  Comments begin with hash in the beginning of the line

   # In this file you specify users responsible for space used by the group
   users: root
   mygroup: chief
   quotagrp: sporkey

Now if warnquota is execute with the -g option, mail will be sendto user "sporkey".

   # warnquota -g /quota

Messages can be customized by editing the "/etc/warnquota.conf" file.

quotactl - C API

You may want to create your own quota tools, especially if youforsee a need to monitor quota data over time, across multiple computers. My database tool of choice for this is SQLitebecause it is very fast, the complete database fits into one file, there is nosetup or administration needed, and databases can be combine. Fordetailed information on using SQLite take a look at the("SQLite Tutorial").

Goal - Create quotadb

The goal is to create the program "quotadb" that will automatically create the necessary database ( a default database quota_database) and tables, for all filesystems and all users on the system. There will also be a "-f <database>" option to place the database file in aparticular location, or just place it in the default directory as "quota_database", if nooptions are specified.

Create tables in /root/quota_database
   # quotadb -f /root/quota_database

Now, after the initial commad is run, quotadb can be run on a peridoic basis to update the entriesin the table. Update is specified with the -u option.

 -u option updates history table
   # quotadb -f /root/quota_database -u

After the tables are created by running "quotadb -f /root/quota_database", quotadb is placed in a cron job and run nightly. To get into the cron editor as roottype "cronjob -e".

#root cronjob. Type cronjob -e 
# This updates history database
#MINUTE(0-59) HOUR(0-23) DAYOFMONTH(1-31) MONTHOFYEAR(1-12) DAYOFWEEK(0-6) Note 0=Sun
2 1        * * *  /usr/local/bin/quotadb  -f /root/quota_database -u

Running this once a day, over a period of time, will populate the database table history, defined below.

     CREATE TABLE history (filesystem varchar(50),
                           name varchar(50), 
                           uid int,
                           b_curr long,
                           b_slimit long,
                           b_hlimit long,
                           i_curr long,
                           i_slimit long,
                           i_hlimit long,
                           timeEnter DATE );

      CREATE TRIGGER insert_history_timeEnter 
                     AFTER  INSERT ON history     
                     BEGIN  UPDATE history 
                     SET timeEnter = DATETIME('NOW','localtime')      
                     WHERE rowid = new.rowid;

The trigger definition above updates the timeEnter field with the currentdate and time. By the way this is localtime, hence the option 'localtime'.The default would give you UTC time.

Structure - if_dqblk

One important structure that gets passed to quotactl is if_dqblk. This isdefined in the file "quota.h", included in the quota_examples.tar.gz. You will not find this structure in #include <linux/quota.h> or "/usr/include/linux/quota.h" on the Fedora distros. Instead, there is a copy of this structure in the "quota-3.12-5.src.rpm".You can get this source rpm as follows:

   $ wget http://download.fedora.redhat.com/pub/fedora/linux/core/3/SRPMS/quota-3.12-5.src.rpm
   $ rpm -K quota-3.12-5.src.rpm
   $ rpm -ivh quota-3.12-5.src.rpm

   $ su
   Password:

   # rpm -ivh quota-3.12-5.src.rpm
   1:quota                  ########################################### [100%]

If you're curious, the "rpm -K" command above checks the signature on the package.

After this installation, the source can be found under "/usr/src/redhat/SOURCES".

   # ls -l /usr/src/redhat/SOURCES/quota-3.12.tar.gz

If you "tar -xzf" this source, you'll see "quota.h", which contains the if_dqblk structure shown below. Note the block hard limit "dqb_bhardlimit", block soft limit "dqb_bsoftlimit", current space taken "dqb_curspace", and similar all 64 bit values for the inode variables as well.

    struct if_dqblk {                      
            u_int64_t dqb_bhardlimit;      
            u_int64_t dqb_bsoftlimit;      
            u_int64_t dqb_curspace;        
            u_int64_t dqb_ihardlimit;      
            u_int64_t dqb_isoftlimit;      
            u_int64_t dqb_curinodes;       
            u_int64_t dqb_btime;           
            u_int64_t dqb_itime;           
            u_int32_t dqb_valid;           
    };                                     

By the way, the Linux kernel source contains a quota.h file as well"/lib/modules/2.6.11-1.35_FC3smp/build/include/linux/quota.h", which hasan identical structure. It cannot be used in a user-land program. Kernel valuesfor 64 bits are defined as __u65 and not u_int64_t; but, you can certainly see these values get passed directly to the kernel.

  /* This is from the kernel source */
    struct if_dqblk {
           __u64 dqb_bhardlimit;
           __u64 dqb_bsoftlimit;
           __u64 dqb_curspace;
           __u64 dqb_ihardlimit;
           __u64 dqb_isoftlimit;
           __u64 dqb_curinodes;
           __u64 dqb_btime;
           __u64 dqb_itime;
           __u32 dqb_valid;
  };

Example Call to quotactl

Below is an example call to quotactl for getting quota spaced used for uid. The variable dq is defined as type struct if_dqblk and it's passed as the last parameter to quotactl. Note the macro QCMD(Q_GETQUOTA, USRQUOTA), passed as the first parameter. Q_GETQUOT, USRQUOTAare defined in "quota.h". The block device, as defined by block_device is the second parameter. And the user id value is defined in uid. The function quotactl returns 0 on success and -1 on failure.

       ...
     	struct if_dqblk dq;
	if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), block_device, uid, (caddr_t) & dq)) {
		perror("quotactl");
		return 1;
	} else {
		printf("Device: %s\n", block_device);
		printf
		    ("Current space:  %7.1qu \tSoft limit: %7.1qu  \tHard limit: %7.1qu \tGrace period: %qu\n",
		     dq.dqb_curspace, dq.dqb_bsoftlimit, dq.dqb_bhardlimit,
		     dq.dqb_btime);
        ...

Set Quota Options

The section above was an example of getting the quota settings. Let's move on to changing or setting the quota options for the user defined in pwd->pw_uid. It helps to have a specific example. Below we will set a block soft limit of 78, block hard limit of 96, inode soft limit of 50, and an inode hard limit of 100. This program starts with a call to getpwname which takes the user name as a string and passes back a passwd structure. The passwd structure contains the user name, password, user id, group id, real name, home directory and shell program for that particular user.

       ...
       const struct passwd *pwd;
       struct if_dqblk dq;      

       if ((pwd = getpwnam(user)) == NULL) {
           printf(stderr, "Invalid -u option \n");
           exit(1);
       }

       dq.dqb_bsoftlimit = 78;
       dq.dqb_bhardlimit = 96;
       dq.dqb_isoftlimit = 50;
       dq.dqb_ihardlimit = 100;

       if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), block_device, pwd->pw_uid, (caddr_t) & dq)) {
            perror("quotactl");
            return 1;
        } 

Again, the full examples can be downloaded from quota_examples.tar.gz


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值