root/ufs/ufs/ufs_quota.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dqref
  2. getinoquota
  3. ufs_quota_alloc_blocks2
  4. ufs_quota_free_blocks2
  5. chkdqchg
  6. ufs_quota_alloc_inode2
  7. ufs_quota_free_inode2
  8. chkiqchg
  9. chkdquot
  10. quotaon_vnode
  11. quotaon
  12. quotaoff_vnode
  13. quotaoff
  14. getquota
  15. setquota
  16. setuse
  17. qsync_vnode
  18. qsync
  19. ufs_quota_init
  20. dqget
  21. dqrele
  22. dqsync
  23. ufs_quota_delete
  24. ufs_quotactl

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

/* [<][>][^][v][top][bottom][index][help] */