home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / ufs / ufs_quota.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-21  |  22.8 KB  |  935 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Robert Elz at The University of Melbourne.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  *    @(#)ufs_quota.c    7.11 (Berkeley) 6/21/91
  37.  */
  38. #include "param.h"
  39. #include "kernel.h"
  40. #include "systm.h"
  41. #include "namei.h"
  42. #include "malloc.h"
  43. #include "file.h"
  44. #include "proc.h"
  45. #include "vnode.h"
  46. #include "mount.h"
  47.  
  48. #include "fs.h"
  49. #include "quota.h"
  50. #include "inode.h"
  51. #include "ufsmount.h"
  52.  
  53. /*
  54.  * Quota name to error message mapping.
  55.  */
  56. static char *quotatypes[] = INITQFNAMES;
  57.  
  58. /*
  59.  * Set up the quotas for an inode.
  60.  *
  61.  * This routine completely defines the semantics of quotas.
  62.  * If other criterion want to be used to establish quotas, the
  63.  * MAXQUOTAS value in quotas.h should be increased, and the
  64.  * additional dquots set up here.
  65.  */
  66. getinoquota(ip)
  67.     register struct inode *ip;
  68. {
  69.     struct ufsmount *ump;
  70.     struct vnode *vp = ITOV(ip);
  71.     int error;
  72.  
  73.     ump = VFSTOUFS(vp->v_mount);
  74.     /*
  75.      * Set up the user quota based on file uid.
  76.      * EINVAL means that quotas are not enabled.
  77.      */
  78.     if (ip->i_dquot[USRQUOTA] == NODQUOT &&
  79.         (error =
  80.         dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
  81.         error != EINVAL)
  82.         return (error);
  83.     /*
  84.      * Set up the group quota based on file gid.
  85.      * EINVAL means that quotas are not enabled.
  86.      */
  87.     if (ip->i_dquot[GRPQUOTA] == NODQUOT &&
  88.         (error =
  89.         dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
  90.         error != EINVAL)
  91.         return (error);
  92.     return (0);
  93. }
  94.  
  95. /*
  96.  * Update disk usage, and take corrective action.
  97.  */
  98. chkdq(ip, change, cred, flags)
  99.     register struct inode *ip;
  100.     long change;
  101.     struct ucred *cred;
  102.     int flags;
  103. {
  104.     register struct dquot *dq;
  105.     register int i;
  106.     int ncurblocks, error;
  107.  
  108. #ifdef DIAGNOSTIC
  109.     if ((flags & CHOWN) == 0)
  110.         chkdquot(ip);
  111. #endif
  112.     if (change == 0)
  113.         return (0);
  114.     if (change < 0) {
  115.         for (i = 0; i < MAXQUOTAS; i++) {
  116.             if ((dq = ip->i_dquot[i]) == NODQUOT)
  117.                 continue;
  118.             while (dq->dq_flags & DQ_LOCK) {
  119.                 dq->dq_flags |= DQ_WANT;
  120.                 sleep((caddr_t)dq, PINOD+1);
  121.             }
  122.             ncurblocks = dq->dq_curblocks + change;
  123.             if (ncurblocks >= 0)
  124.                 dq->dq_curblocks = ncurblocks;
  125.             else
  126.                 dq->dq_curblocks = 0;
  127.             dq->dq_flags &= ~DQ_BLKS;
  128.             dq->dq_flags |= DQ_MOD;
  129.         }
  130.         return (0);
  131.     }
  132.     if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
  133.         for (i = 0; i < MAXQUOTAS; i++) {
  134.             if ((dq = ip->i_dquot[i]) == NODQUOT)
  135.                 continue;
  136.             if (error = chkdqchg(ip, change, cred, i))
  137.                 return (error);
  138.         }
  139.     }
  140.     for (i = 0; i < MAXQUOTAS; i++) {
  141.         if ((dq = ip->i_dquot[i]) == NODQUOT)
  142.             continue;
  143.         while (dq->dq_flags & DQ_LOCK) {
  144.             dq->dq_flags |= DQ_WANT;
  145.             sleep((caddr_t)dq, PINOD+1);
  146.         }
  147.         dq->dq_curblocks += change;
  148.         dq->dq_flags |= DQ_MOD;
  149.     }
  150.     return (0);
  151. }
  152.  
  153. /*
  154.  * Check for a valid change to a users allocation.
  155.  * Issue an error message if appropriate.
  156.  */
  157. chkdqchg(ip, change, cred, type)
  158.     struct inode *ip;
  159.     long change;
  160.     struct ucred *cred;
  161.     int type;
  162. {
  163.     register struct dquot *dq = ip->i_dquot[type];
  164.     long ncurblocks = dq->dq_curblocks + change;
  165.  
  166.     /*
  167.      * If user would exceed their hard limit, disallow space allocation.
  168.      */
  169.     if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
  170.         if ((dq->dq_flags & DQ_BLKS) == 0 &&
  171.             ip->i_uid == cred->cr_uid) {
  172.             uprintf("\n%s: write failed, %s disk limit reached\n",
  173.                 ip->i_fs->fs_fsmnt, quotatypes[type]);
  174.             dq->dq_flags |= DQ_BLKS;
  175.         }
  176.         return (EDQUOT);
  177.     }
  178.     /*
  179.      * If user is over their soft limit for too long, disallow space
  180.      * allocation. Reset time limit as they cross their soft limit.
  181.      */
  182.     if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
  183.         if (dq->dq_curblocks < dq->dq_bsoftlimit) {
  184.             dq->dq_btime = time.tv_sec +
  185.                 VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type];
  186.             if (ip->i_uid == cred->cr_uid)
  187.                 uprintf("\n%s: warning, %s %s\n",
  188.                     ip->i_fs->fs_fsmnt, quotatypes[type],
  189.                     "disk quota exceeded");
  190.             return (0);
  191.         }
  192.         if (time.tv_sec > dq->dq_btime) {
  193.             if ((dq->dq_flags & DQ_BLKS) == 0 &&
  194.                 ip->i_uid == cred->cr_uid) {
  195.                 uprintf("\n%s: write failed, %s %s\n",
  196.                     ip->i_fs->fs_fsmnt, quotatypes[type],
  197.                     "disk quota exceeded too long");
  198.                 dq->dq_flags |= DQ_BLKS;
  199.             }
  200.             return (EDQUOT);
  201.         }
  202.     }
  203.     return (0);
  204. }
  205.  
  206. /*
  207.  * Check the inode limit, applying corrective action.
  208.  */
  209. chkiq(ip, change, cred, flags)
  210.     register struct inode *ip;
  211.     long change;
  212.     struct ucred *cred;
  213.     int flags;
  214. {
  215.     register struct dquot *dq;
  216.     register int i;
  217.     int ncurinodes, error;
  218.  
  219. #ifdef DIAGNOSTIC
  220.     if ((flags & CHOWN) == 0)
  221.         chkdquot(ip);
  222. #endif
  223.     if (change == 0)
  224.         return (0);
  225.     if (change < 0) {
  226.         for (i = 0; i < MAXQUOTAS; i++) {
  227.             if ((dq = ip->i_dquot[i]) == NODQUOT)
  228.                 continue;
  229.             while (dq->dq_flags & DQ_LOCK) {
  230.                 dq->dq_flags |= DQ_WANT;
  231.                 sleep((caddr_t)dq, PINOD+1);
  232.             }
  233.             ncurinodes = dq->dq_curinodes + change;
  234.             if (ncurinodes >= 0)
  235.                 dq->dq_curinodes = ncurinodes;
  236.             else
  237.                 dq->dq_curinodes = 0;
  238.             dq->dq_flags &= ~DQ_INODS;
  239.             dq->dq_flags |= DQ_MOD;
  240.         }
  241.         return (0);
  242.     }
  243.     if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
  244.         for (i = 0; i < MAXQUOTAS; i++) {
  245.             if ((dq = ip->i_dquot[i]) == NODQUOT)
  246.                 continue;
  247.             if (error = chkiqchg(ip, change, cred, i))
  248.                 return (error);
  249.         }
  250.     }
  251.     for (i = 0; i < MAXQUOTAS; i++) {
  252.         if ((dq = ip->i_dquot[i]) == NODQUOT)
  253.             continue;
  254.         while (dq->dq_flags & DQ_LOCK) {
  255.             dq->dq_flags |= DQ_WANT;
  256.             sleep((caddr_t)dq, PINOD+1);
  257.         }
  258.         dq->dq_curinodes += change;
  259.         dq->dq_flags |= DQ_MOD;
  260.     }
  261.     return (0);
  262. }
  263.  
  264. /*
  265.  * Check for a valid change to a users allocation.
  266.  * Issue an error message if appropriate.
  267.  */
  268. chkiqchg(ip, change, cred, type)
  269.     struct inode *ip;
  270.     long change;
  271.     struct ucred *cred;
  272.     int type;
  273. {
  274.     register struct dquot *dq = ip->i_dquot[type];
  275.     long ncurinodes = dq->dq_curinodes + change;
  276.  
  277.     /*
  278.      * If user would exceed their hard limit, disallow inode allocation.
  279.      */
  280.     if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
  281.         if ((dq->dq_flags & DQ_INODS) == 0 &&
  282.             ip->i_uid == cred->cr_uid) {
  283.             uprintf("\n%s: write failed, %s inode limit reached\n",
  284.                 ip->i_fs->fs_fsmnt, quotatypes[type]);
  285.             dq->dq_flags |= DQ_INODS;
  286.         }
  287.         return (EDQUOT);
  288.     }
  289.     /*
  290.      * If user is over their soft limit for too long, disallow inode
  291.      * allocation. Reset time limit as they cross their soft limit.
  292.      */
  293.     if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
  294.         if (dq->dq_curinodes < dq->dq_isoftlimit) {
  295.             dq->dq_itime = time.tv_sec +
  296.                 VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type];
  297.             if (ip->i_uid == cred->cr_uid)
  298.                 uprintf("\n%s: warning, %s %s\n",
  299.                     ip->i_fs->fs_fsmnt, quotatypes[type],
  300.                     "inode quota exceeded");
  301.             return (0);
  302.         }
  303.         if (time.tv_sec > dq->dq_itime) {
  304.             if ((dq->dq_flags & DQ_INODS) == 0 &&
  305.                 ip->i_uid == cred->cr_uid) {
  306.                 uprintf("\n%s: write failed, %s %s\n",
  307.                     ip->i_fs->fs_fsmnt, quotatypes[type],
  308.                     "inode quota exceeded too long");
  309.                 dq->dq_flags |= DQ_INODS;
  310.             }
  311.             return (EDQUOT);
  312.         }
  313.     }
  314.     return (0);
  315. }
  316.  
  317. #ifdef DIAGNOSTIC
  318. /*
  319.  * On filesystems with quotas enabled,
  320.  * it is an error for a file to change size and not
  321.  * to have a dquot structure associated with it.
  322.  */
  323. chkdquot(ip)
  324.     register struct inode *ip;
  325. {
  326.     struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount);
  327.     register int i;
  328.  
  329.     for (i = 0; i < MAXQUOTAS; i++) {
  330.         if (ump->um_quotas[i] == NULLVP ||
  331.             (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
  332.             continue;
  333.         if (ip->i_dquot[i] == NODQUOT) {
  334.             vprint("chkdquot: missing dquot", ITOV(ip));
  335.             panic("missing dquot");
  336.         }
  337.     }
  338. }
  339. #endif /* DIAGNOSTIC */
  340.  
  341. /*
  342.  * Code to process quotactl commands.
  343.  */
  344.  
  345. /*
  346.  * Q_QUOTAON - set up a quota file for a particular file system.
  347.  */
  348. quotaon(p, mp, type, fname)
  349.     struct proc *p;
  350.     struct mount *mp;
  351.     register int type;
  352.     caddr_t fname;
  353. {
  354.     register struct ufsmount *ump = VFSTOUFS(mp);
  355.     register struct vnode *vp, **vpp;
  356.     struct vnode *nextvp;
  357.     struct dquot *dq;
  358.     int error;
  359.     struct nameidata nd;
  360.  
  361.     vpp = &ump->um_quotas[type];
  362.     nd.ni_segflg = UIO_USERSPACE;
  363.     nd.ni_dirp = fname;
  364.     if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
  365.         return (error);
  366.     vp = nd.ni_vp;
  367.     VOP_UNLOCK(vp);
  368.     if (vp->v_type != VREG) {
  369.         (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
  370.         return (EACCES);
  371.     }
  372.     if (vfs_busy(mp)) {
  373.         (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
  374.         return (EBUSY);
  375.     }
  376.     if (*vpp != vp)
  377.         quotaoff(p, mp, type);
  378.     ump->um_qflags[type] |= QTF_OPENING;
  379.     mp->mnt_flag |= MNT_QUOTA;
  380.     vp->v_flag |= VSYSTEM;
  381.     *vpp = vp;
  382.     /*
  383.      * Save the credential of the process that turned on quotas.
  384.      * Set up the time limits for this quota.
  385.      */
  386.     crhold(p->p_ucred);
  387.     ump->um_cred[type] = p->p_ucred;
  388.     ump->um_btime[type] = MAX_DQ_TIME;
  389.     ump->um_itime[type] = MAX_IQ_TIME;
  390.     if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
  391.         if (dq->dq_btime > 0)
  392.             ump->um_btime[type] = dq->dq_btime;
  393.         if (dq->dq_itime > 0)
  394.             ump->um_itime[type] = dq->dq_itime;
  395.         dqrele(NULLVP, dq);
  396.     }
  397.     /*
  398.      * Search vnodes associated with this mount point,
  399.      * adding references to quota file being opened.
  400.      * NB: only need to add dquot's for inodes being modified.
  401.      */
  402. again:
  403.     for (vp = mp->mnt_mounth; vp; vp = nextvp) {
  404.         nextvp = vp->v_mountf;
  405.         if (vp->v_writecount == 0)
  406.             continue;
  407.         if (vget(vp))
  408.             goto again;
  409.         if (error = getinoquota(VTOI(vp))) {
  410.             vput(vp);
  411.             break;
  412.         }
  413.         vput(vp);
  414.         if (vp->v_mountf != nextvp || vp->v_mount != mp)
  415.             goto again;
  416.     }
  417.     ump->um_qflags[type] &= ~QTF_OPENING;
  418.     if (error)
  419.         quotaoff(p, mp, type);
  420.     vfs_unbusy(mp);
  421.     return (error);
  422. }
  423.  
  424. /*
  425.  * Q_QUOTAOFF - turn off disk quotas for a filesystem.
  426.  */
  427. quotaoff(p, mp, type)
  428.     struct proc *p;
  429.     struct mount *mp;
  430.     register int type;
  431. {
  432.     register struct vnode *vp;
  433.     struct vnode *qvp, *nextvp;
  434.     struct ufsmount *ump = VFSTOUFS(mp);
  435.     register struct dquot *dq;
  436.     register struct inode *ip;
  437.     int error;
  438.     
  439.     if ((mp->mnt_flag & MNT_MPBUSY) == 0)
  440.         panic("quotaoff: not busy");
  441.     if ((qvp = ump->um_quotas[type]) == NULLVP)
  442.         return (0);
  443.     ump->um_qflags[type] |= QTF_CLOSING;
  444.     /*
  445.      * Search vnodes associated with this mount point,
  446.      * deleting any references to quota file being closed.
  447.      */
  448. again:
  449.     for (vp = mp->mnt_mounth; vp; vp = nextvp) {
  450.         nextvp = vp->v_mountf;
  451.         if (vget(vp))
  452.             goto again;
  453.         ip = VTOI(vp);
  454.         dq = ip->i_dquot[type];
  455.         ip->i_dquot[type] = NODQUOT;
  456.         dqrele(vp, dq);
  457.         vput(vp);
  458.         if (vp->v_mountf != nextvp || vp->v_mount != mp)
  459.             goto again;
  460.     }
  461.     dqflush(qvp);
  462.     qvp->v_flag &= ~VSYSTEM;
  463.     error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);
  464.     ump->um_quotas[type] = NULLVP;
  465.     crfree(ump->um_cred[type]);
  466.     ump->um_cred[type] = NOCRED;
  467.     ump->um_qflags[type] &= ~QTF_CLOSING;
  468.     for (type = 0; type < MAXQUOTAS; type++)
  469.         if (ump->um_quotas[type] != NULLVP)
  470.             break;
  471.     if (type == MAXQUOTAS)
  472.         mp->mnt_flag &= ~MNT_QUOTA;
  473.     return (error);
  474. }
  475.  
  476. /*
  477.  * Q_GETQUOTA - return current values in a dqblk structure.
  478.  */
  479. getquota(mp, id, type, addr)
  480.     struct mount *mp;
  481.     u_long id;
  482.     int type;
  483.     caddr_t addr;
  484. {
  485.     struct dquot *dq;
  486.     int error;
  487.  
  488.     if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq))
  489.         return (error);
  490.     error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));
  491.     dqrele(NULLVP, dq);
  492.     return (error);
  493. }
  494.  
  495. /*
  496.  * Q_SETQUOTA - assign an entire dqblk structure.
  497.  */
  498. setquota(mp, id, type, addr)
  499.     struct mount *mp;
  500.     u_long id;
  501.     int type;
  502.     caddr_t addr;
  503. {
  504.     register struct dquot *dq;
  505.     struct dquot *ndq;
  506.     struct ufsmount *ump = VFSTOUFS(mp);
  507.     struct dqblk newlim;
  508.     int error;
  509.  
  510.     if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))
  511.         return (error);
  512.     if (error = dqget(NULLVP, id, ump, type, &ndq))
  513.         return (error);
  514.     dq = ndq;
  515.     while (dq->dq_flags & DQ_LOCK) {
  516.         dq->dq_flags |= DQ_WANT;
  517.         sleep((caddr_t)dq, PINOD+1);
  518.     }
  519.     /*
  520.      * Copy all but the current values.
  521.      * Reset time limit if previously had no soft limit or were
  522.      * under it, but now have a soft limit and are over it.
  523.      */
  524.     newlim.dqb_curblocks = dq->dq_curblocks;
  525.     newlim.dqb_curinodes = dq->dq_curinodes;
  526.     if (dq->dq_id != 0) {
  527.         newlim.dqb_btime = dq->dq_btime;
  528.         newlim.dqb_itime = dq->dq_itime;
  529.     }
  530.     if (newlim.dqb_bsoftlimit &&
  531.         dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
  532.         (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
  533.         newlim.dqb_btime = time.tv_sec + ump->um_btime[type];
  534.     if (newlim.dqb_isoftlimit &&
  535.         dq->dq_curinodes >= newlim.dqb_isoftlimit &&
  536.         (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
  537.         newlim.dqb_itime = time.tv_sec + ump->um_itime[type];
  538.     dq->dq_dqb = newlim;
  539.     if (dq->dq_curblocks < dq->dq_bsoftlimit)
  540.         dq->dq_flags &= ~DQ_BLKS;
  541.     if (dq->dq_curinodes < dq->dq_isoftlimit)
  542.         dq->dq_flags &= ~DQ_INODS;
  543.     if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
  544.         dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
  545.         dq->dq_flags |= DQ_FAKE;
  546.     else
  547.         dq->dq_flags &= ~DQ_FAKE;
  548.     dq->dq_flags |= DQ_MOD;
  549.     dqrele(NULLVP, dq);
  550.     return (0);
  551. }
  552.  
  553. /*
  554.  * Q_SETUSE - set current inode and block usage.
  555.  */
  556. setuse(mp, id, type, addr)
  557.     struct mount *mp;
  558.     u_long id;
  559.     int type;
  560.     caddr_t addr;
  561. {
  562.     register struct dquot *dq;
  563.     struct ufsmount *ump = VFSTOUFS(mp);
  564.     struct dquot *ndq;
  565.     struct dqblk usage;
  566.     int error;
  567.  
  568.     if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))
  569.         return (error);
  570.     if (error = dqget(NULLVP, id, ump, type, &ndq))
  571.         return (error);
  572.     dq = ndq;
  573.     while (dq->dq_flags & DQ_LOCK) {
  574.         dq->dq_flags |= DQ_WANT;
  575.         sleep((caddr_t)dq, PINOD+1);
  576.     }
  577.     /*
  578.      * Reset time limit if have a soft limit and were
  579.      * previously under it, but are now over it.
  580.      */
  581.     if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
  582.         usage.dqb_curblocks >= dq->dq_bsoftlimit)
  583.         dq->dq_btime = time.tv_sec + ump->um_btime[type];
  584.     if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
  585.         usage.dqb_curinodes >= dq->dq_isoftlimit)
  586.         dq->dq_itime = time.tv_sec + ump->um_itime[type];
  587.     dq->dq_curblocks = usage.dqb_curblocks;
  588.     dq->dq_curinodes = usage.dqb_curinodes;
  589.     if (dq->dq_curblocks < dq->dq_bsoftlimit)
  590.         dq->dq_flags &= ~DQ_BLKS;
  591.     if (dq->dq_curinodes < dq->dq_isoftlimit)
  592.         dq->dq_flags &= ~DQ_INODS;
  593.     dq->dq_flags |= DQ_MOD;
  594.     dqrele(NULLVP, dq);
  595.     return (0);
  596. }
  597.  
  598. /*
  599.  * Q_SYNC - sync quota files to disk.
  600.  */
  601. qsync(mp)
  602.     struct mount *mp;
  603. {
  604.     struct ufsmount *ump = VFSTOUFS(mp);
  605.     register struct vnode *vp, *nextvp;
  606.     register struct dquot *dq;
  607.     register int i;
  608.  
  609.     /*
  610.      * Check if the mount point has any quotas.
  611.      * If not, simply return.
  612.      */
  613.     if ((mp->mnt_flag & MNT_MPBUSY) == 0)
  614.         panic("qsync: not busy");
  615.     for (i = 0; i < MAXQUOTAS; i++)
  616.         if (ump->um_quotas[i] != NULLVP)
  617.             break;
  618.     if (i == MAXQUOTAS)
  619.         return (0);
  620.     /*
  621.      * Search vnodes associated with this mount point,
  622.      * synchronizing any modified dquot structures.
  623.      */
  624. again:
  625.     for (vp = mp->mnt_mounth; vp; vp = nextvp) {
  626.         nextvp = vp->v_mountf;
  627.         if (VOP_ISLOCKED(vp))
  628.             continue;
  629.         if (vget(vp))
  630.             goto again;
  631.         for (i = 0; i < MAXQUOTAS; i++) {
  632.             dq = VTOI(vp)->i_dquot[i];
  633.             if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
  634.                 dqsync(vp, dq);
  635.         }
  636.         vput(vp);
  637.         if (vp->v_mountf != nextvp || vp->v_mount != mp)
  638.             goto again;
  639.     }
  640.     return (0);
  641. }
  642.  
  643. /*
  644.  * Code pertaining to management of the in-core dquot data structures.
  645.  */
  646.  
  647. /*
  648.  * Dquot cache - hash chain headers.
  649.  */
  650. union    dqhead    {
  651.     union    dqhead    *dqh_head[2];
  652.     struct    dquot    *dqh_chain[2];
  653. };
  654. #define    dqh_forw    dqh_chain[0]
  655. #define    dqh_back    dqh_chain[1]
  656.  
  657. union dqhead *dqhashtbl;
  658. long dqhash;
  659.  
  660. /*
  661.  * Dquot free list.
  662.  */
  663. #define    DQUOTINC    5    /* minimum free dquots desired */
  664. struct dquot *dqfreel, **dqback = &dqfreel;
  665. long numdquot, desireddquot = DQUOTINC;
  666.  
  667. /*
  668.  * Initialize the quota system.
  669.  */
  670. dqinit()
  671. {
  672.     register union dqhead *dhp;
  673.     register long dqhashsize;
  674.  
  675.     dqhashsize = roundup((desiredvnodes + 1) * sizeof *dhp / 2,
  676.         NBPG * CLSIZE);
  677.     dqhashtbl = (union dqhead *)malloc(dqhashsize, M_DQUOT, M_WAITOK);
  678.     for (dqhash = 1; dqhash <= dqhashsize / sizeof *dhp; dqhash <<= 1)
  679.         /* void */;
  680.     dqhash = (dqhash >> 1) - 1;
  681.     for (dhp = &dqhashtbl[dqhash]; dhp >= dqhashtbl; dhp--) {
  682.         dhp->dqh_head[0] = dhp;
  683.         dhp->dqh_head[1] = dhp;
  684.     }
  685. }
  686.  
  687. /*
  688.  * Obtain a dquot structure for the specified identifier and quota file
  689.  * reading the information from the file if necessary.
  690.  */
  691. dqget(vp, id, ump, type, dqp)
  692.     struct vnode *vp;
  693.     u_long id;
  694.     register struct ufsmount *ump;
  695.     register int type;
  696.     struct dquot **dqp;
  697. {
  698.     register struct dquot *dq;
  699.     register union dqhead *dh;
  700.     register struct dquot *dp;
  701.     register struct vnode *dqvp;
  702.     struct iovec aiov;
  703.     struct uio auio;
  704.     int error;
  705.  
  706.     dqvp = ump->um_quotas[type];
  707.     if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
  708.         *dqp = NODQUOT;
  709.         return (EINVAL);
  710.     }
  711.     /*
  712.      * Check the cache first.
  713.      */
  714.     dh = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash];
  715.     for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = dq->dq_forw) {
  716.         if (dq->dq_id != id ||
  717.             dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
  718.             continue;
  719.         /*
  720.          * Cache hit with no references.  Take
  721.          * the structure off the free list.
  722.          */
  723.         if (dq->dq_cnt == 0) {
  724.             dp = dq->dq_freef;
  725.             if (dp != NODQUOT)
  726.                 dp->dq_freeb = dq->dq_freeb;
  727.             else
  728.                 dqback = dq->dq_freeb;
  729.             *dq->dq_freeb = dp;
  730.         }
  731.         DQREF(dq);
  732.         *dqp = dq;
  733.         return (0);
  734.     }
  735.     /*
  736.      * Not in cache, allocate a new one.
  737.      */
  738.     if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes)
  739.         desireddquot += DQUOTINC;
  740.     if (numdquot < desireddquot) {
  741.         dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK);
  742.         bzero((char *)dq, sizeof *dq);
  743.         numdquot++;
  744.     } else {
  745.         if ((dq = dqfreel) == NULL) {
  746.             tablefull("dquot");
  747.             *dqp = NODQUOT;
  748.             return (EUSERS);
  749.         }
  750.         if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
  751.             panic("free dquot isn't");
  752.         if ((dp = dq->dq_freef) != NODQUOT)
  753.             dp->dq_freeb = &dqfreel;
  754.         else
  755.             dqback = &dqfreel;
  756.         dqfreel = dp;
  757.         dq->dq_freef = NULL;
  758.         dq->dq_freeb = NULL;
  759.         remque(dq);
  760.     }
  761.     /*
  762.      * Initialize the contents of the dquot structure.
  763.      */
  764.     if (vp != dqvp)
  765.         VOP_LOCK(dqvp);
  766.     insque(dq, dh);
  767.     DQREF(dq);
  768.     dq->dq_flags = DQ_LOCK;
  769.     dq->dq_id = id;
  770.     dq->dq_ump = ump;
  771.     dq->dq_type = type;
  772.     auio.uio_iov = &aiov;
  773.     auio.uio_iovcnt = 1;
  774.     aiov.iov_base = (caddr_t)&dq->dq_dqb;
  775.     aiov.iov_len = sizeof (struct dqblk);
  776.     auio.uio_resid = sizeof (struct dqblk);
  777.     auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
  778.     auio.uio_segflg = UIO_SYSSPACE;
  779.     auio.uio_rw = UIO_READ;
  780.     auio.uio_procp = (struct proc *)0;
  781.     error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
  782.     if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
  783.         bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk));
  784.     if (vp != dqvp)
  785.         VOP_UNLOCK(dqvp);
  786.     if (dq->dq_flags & DQ_WANT)
  787.         wakeup((caddr_t)dq);
  788.     dq->dq_flags = 0;
  789.     /*
  790.      * I/O error in reading quota file, release
  791.      * quota structure and reflect problem to caller.
  792.      */
  793.     if (error) {
  794.         remque(dq);
  795.         dq->dq_forw = dq;    /* on a private, unfindable hash list */
  796.         dq->dq_back = dq;
  797.         dqrele(vp, dq);
  798.         *dqp = NODQUOT;
  799.         return (error);
  800.     }
  801.     /*
  802.      * Check for no limit to enforce.
  803.      * Initialize time values if necessary.
  804.      */
  805.     if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
  806.         dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
  807.         dq->dq_flags |= DQ_FAKE;
  808.     if (dq->dq_id != 0) {
  809.         if (dq->dq_btime == 0)
  810.             dq->dq_btime = time.tv_sec + ump->um_btime[type];
  811.         if (dq->dq_itime == 0)
  812.             dq->dq_itime = time.tv_sec + ump->um_itime[type];
  813.     }
  814.     *dqp = dq;
  815.     return (0);
  816. }
  817.  
  818. /*
  819.  * Obtain a reference to a dquot.
  820.  */
  821. dqref(dq)
  822.     struct dquot *dq;
  823. {
  824.  
  825.     dq->dq_cnt++;
  826. }
  827.  
  828. /*
  829.  * Release a reference to a dquot.
  830.  */
  831. dqrele(vp, dq)
  832.     struct vnode *vp;
  833.     register struct dquot *dq;
  834. {
  835.  
  836.     if (dq == NODQUOT)
  837.         return;
  838.     if (dq->dq_cnt > 1) {
  839.         dq->dq_cnt--;
  840.         return;
  841.     }
  842.     if (dq->dq_flags & DQ_MOD)
  843.         (void) dqsync(vp, dq);
  844.     if (--dq->dq_cnt > 0)
  845.         return;
  846.     if (dqfreel != NODQUOT) {
  847.         *dqback = dq;
  848.         dq->dq_freeb = dqback;
  849.     } else {
  850.         dqfreel = dq;
  851.         dq->dq_freeb = &dqfreel;
  852.     }
  853.     dq->dq_freef = NODQUOT;
  854.     dqback = &dq->dq_freef;
  855. }
  856.  
  857. /*
  858.  * Update the disk quota in the quota file.
  859.  */
  860. dqsync(vp, dq)
  861.     struct vnode *vp;
  862.     register struct dquot *dq;
  863. {
  864.     struct vnode *dqvp;
  865.     struct iovec aiov;
  866.     struct uio auio;
  867.     int error;
  868.  
  869.     if (dq == NODQUOT)
  870.         panic("dqsync: dquot");
  871.     if ((dq->dq_flags & DQ_MOD) == 0)
  872.         return (0);
  873.     if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
  874.         panic("dqsync: file");
  875.     if (vp != dqvp)
  876.         VOP_LOCK(dqvp);
  877.     while (dq->dq_flags & DQ_LOCK) {
  878.         dq->dq_flags |= DQ_WANT;
  879.         sleep((caddr_t)dq, PINOD+2);
  880.         if ((dq->dq_flags & DQ_MOD) == 0) {
  881.             if (vp != dqvp)
  882.                 VOP_UNLOCK(dqvp);
  883.             return (0);
  884.         }
  885.     }
  886.     dq->dq_flags |= DQ_LOCK;
  887.     auio.uio_iov = &aiov;
  888.     auio.uio_iovcnt = 1;
  889.     aiov.iov_base = (caddr_t)&dq->dq_dqb;
  890.     aiov.iov_len = sizeof (struct dqblk);
  891.     auio.uio_resid = sizeof (struct dqblk);
  892.     auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
  893.     auio.uio_segflg = UIO_SYSSPACE;
  894.     auio.uio_rw = UIO_WRITE;
  895.     auio.uio_procp = (struct proc *)0;
  896.     error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
  897.     if (auio.uio_resid && error == 0)
  898.         error = EIO;
  899.     if (dq->dq_flags & DQ_WANT)
  900.         wakeup((caddr_t)dq);
  901.     dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);
  902.     if (vp != dqvp)
  903.         VOP_UNLOCK(dqvp);
  904.     return (error);
  905. }
  906.  
  907. /*
  908.  * Flush all entries from the cache for a particular vnode.
  909.  */
  910. dqflush(vp)
  911.     register struct vnode *vp;
  912. {
  913.     register union dqhead *dh;
  914.     register struct dquot *dq, *nextdq;
  915.  
  916.     /*
  917.      * Move all dquot's that used to refer to this quota
  918.      * file off their hash chains (they will eventually
  919.      * fall off the head of the free list and be re-used).
  920.      */
  921.     for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) {
  922.         for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) {
  923.             nextdq = dq->dq_forw;
  924.             if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
  925.                 continue;
  926.             if (dq->dq_cnt)
  927.                 panic("dqflush: stray dquot");
  928.             remque(dq);
  929.             dq->dq_forw = dq;
  930.             dq->dq_back = dq;
  931.             dq->dq_ump = (struct ufsmount *)0;
  932.         }
  933.     }
  934. }
  935.