The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_quota.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * Copyright (c) 1982, 1986, 1990, 1993, 1995
   27  *      The Regents of the University of California.  All rights reserved.
   28  *
   29  * This code is derived from software contributed to Berkeley by
   30  * Robert Elz at The University of Melbourne.
   31  *
   32  * Redistribution and use in source and binary forms, with or without
   33  * modification, are permitted provided that the following conditions
   34  * are met:
   35  * 1. Redistributions of source code must retain the above copyright
   36  *    notice, this list of conditions and the following disclaimer.
   37  * 2. Redistributions in binary form must reproduce the above copyright
   38  *    notice, this list of conditions and the following disclaimer in the
   39  *    documentation and/or other materials provided with the distribution.
   40  * 3. All advertising materials mentioning features or use of this software
   41  *    must display the following acknowledgement:
   42  *      This product includes software developed by the University of
   43  *      California, Berkeley and its contributors.
   44  * 4. Neither the name of the University nor the names of its contributors
   45  *    may be used to endorse or promote products derived from this software
   46  *    without specific prior written permission.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  *      @(#)hfs_quota.c
   61  *      derived from @(#)ufs_quota.c    8.5 (Berkeley) 5/20/95
   62  */
   63 
   64 #include <sys/param.h>
   65 #include <sys/kernel.h>
   66 #include <sys/systm.h>
   67 #include <sys/mount.h>
   68 #include <sys/namei.h>
   69 #include <sys/malloc.h>
   70 #include <sys/file.h>
   71 #include <sys/proc.h>
   72 #include <sys/vnode.h>
   73 #include <sys/quota.h>
   74 
   75 #include <hfs/hfs.h>
   76 #include <hfs/hfs_cnode.h>
   77 #include <hfs/hfs_quota.h>
   78 #include <hfs/hfs_mount.h>
   79 
   80 /*
   81  * Quota name to error message mapping.
   82  */
   83 static char *quotatypes[] = INITQFNAMES;
   84 
   85 /*
   86  * Set up the quotas for a cnode.
   87  *
   88  * This routine completely defines the semantics of quotas.
   89  * If other criterion want to be used to establish quotas, the
   90  * MAXQUOTAS value in quotas.h should be increased, and the
   91  * additional dquots set up here.
   92  */
   93 int
   94 hfs_getinoquota(cp)
   95         register struct cnode *cp;
   96 {
   97         struct hfsmount *hfsmp;
   98         struct vnode *vp;
   99         int error;
  100 
  101         vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
  102         hfsmp = VFSTOHFS(vp->v_mount);
  103         /*
  104          * Set up the user quota based on file uid.
  105          * EINVAL means that quotas are not enabled.
  106          */
  107         if (cp->c_dquot[USRQUOTA] == NODQUOT &&
  108             (error =
  109                 dqget(vp, cp->c_uid, &hfsmp->hfs_qfiles[USRQUOTA], USRQUOTA, &cp->c_dquot[USRQUOTA])) &&
  110             error != EINVAL)
  111                 return (error);
  112         /*
  113          * Set up the group quota based on file gid.
  114          * EINVAL means that quotas are not enabled.
  115          */
  116         if (cp->c_dquot[GRPQUOTA] == NODQUOT &&
  117             (error =
  118                 dqget(vp, cp->c_gid,  &hfsmp->hfs_qfiles[GRPQUOTA], GRPQUOTA, &cp->c_dquot[GRPQUOTA])) &&
  119             error != EINVAL)
  120                 return (error);
  121         return (0);
  122 }
  123 
  124 /*
  125  * Update disk usage, and take corrective action.
  126  */
  127 int
  128 hfs_chkdq(cp, change, cred, flags)
  129         register struct cnode *cp;
  130         int64_t change;
  131         struct ucred *cred;
  132         int flags;
  133 {
  134         register struct dquot *dq;
  135         register int i;
  136         int64_t ncurbytes;
  137         int error=0;
  138         struct proc *p;
  139 
  140 #if DIAGNOSTIC
  141         if ((flags & CHOWN) == 0)
  142                 hfs_chkdquot(cp);
  143 #endif
  144         if (change == 0)
  145                 return (0);
  146         if (change < 0) {
  147                 for (i = 0; i < MAXQUOTAS; i++) {
  148                         if ((dq = cp->c_dquot[i]) == NODQUOT)
  149                                 continue;
  150                         while (dq->dq_flags & DQ_LOCK) {
  151                                 dq->dq_flags |= DQ_WANT;
  152                                 sleep((caddr_t)dq, PINOD+1);
  153                         }
  154                         ncurbytes = dq->dq_curbytes + change;
  155                         if (ncurbytes >= 0)
  156                                 dq->dq_curbytes = ncurbytes;
  157                         else
  158                                 dq->dq_curbytes = 0;
  159                         dq->dq_flags &= ~DQ_BLKS;
  160                         dq->dq_flags |= DQ_MOD;
  161                 }
  162                 return (0);
  163         }
  164         p = current_proc();
  165         if (cred == NOCRED)
  166                 cred = kernproc->p_ucred;
  167         if ((cred->cr_uid != 0) || (p->p_flag & P_FORCEQUOTA)) {
  168                 for (i = 0; i < MAXQUOTAS; i++) {
  169                         if ((dq = cp->c_dquot[i]) == NODQUOT)
  170                                 continue;
  171                         error = hfs_chkdqchg(cp, change, cred, i);
  172                         if (error) {
  173                                 break;
  174                         }
  175                 }
  176         }
  177         if ((flags & FORCE) || error == 0) {
  178                 for (i = 0; i < MAXQUOTAS; i++) {
  179                         if ((dq = cp->c_dquot[i]) == NODQUOT)
  180                                 continue;
  181                         while (dq->dq_flags & DQ_LOCK) {
  182                                 dq->dq_flags |= DQ_WANT;
  183                                 sleep((caddr_t)dq, PINOD+1);
  184                         }
  185                         dq->dq_curbytes += change;
  186                         dq->dq_flags |= DQ_MOD;
  187                 }
  188         }
  189         return (error);
  190 }
  191 
  192 /*
  193  * Check for a valid change to a users allocation.
  194  * Issue an error message if appropriate.
  195  */
  196 int
  197 hfs_chkdqchg(cp, change, cred, type)
  198         struct cnode *cp;
  199         int64_t change;
  200         struct ucred *cred;
  201         int type;
  202 {
  203         register struct dquot *dq = cp->c_dquot[type];
  204         u_int64_t ncurbytes = dq->dq_curbytes + change;
  205         struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
  206 
  207         /*
  208          * If user would exceed their hard limit, disallow space allocation.
  209          */
  210         if (ncurbytes >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
  211                 if ((dq->dq_flags & DQ_BLKS) == 0 &&
  212                     cp->c_uid == cred->cr_uid) {
  213 #if 0   
  214                         printf("\n%s: write failed, %s disk limit reached\n",
  215                             vp->v_mount->mnt_stat.f_mntonname,
  216                             quotatypes[type]);
  217 #endif
  218                         dq->dq_flags |= DQ_BLKS;
  219                 }
  220                 return (EDQUOT);
  221         }
  222         /*
  223          * If user is over their soft limit for too long, disallow space
  224          * allocation. Reset time limit as they cross their soft limit.
  225          */
  226         if (ncurbytes >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
  227                 if (dq->dq_curbytes < dq->dq_bsoftlimit) {
  228                         dq->dq_btime = time.tv_sec +
  229                             VFSTOHFS(vp->v_mount)->hfs_qfiles[type].qf_btime;
  230 #if 0
  231                         if (cp->c_uid == cred->cr_uid)
  232                                 printf("\n%s: warning, %s %s\n",
  233                                     vp->v_mount->mnt_stat.f_mntonname,
  234                                     quotatypes[type], "disk quota exceeded");
  235 #endif
  236                         return (0);
  237                 }
  238                 if (time.tv_sec > dq->dq_btime) {
  239                         if ((dq->dq_flags & DQ_BLKS) == 0 &&
  240                             cp->c_uid == cred->cr_uid) {
  241 #if 0
  242                                 printf("\n%s: write failed, %s %s\n",
  243                                     vp->v_mount->mnt_stat.f_mntonname,
  244                                     quotatypes[type],
  245                                     "disk quota exceeded for too long");
  246 #endif
  247                                 dq->dq_flags |= DQ_BLKS;
  248                         }
  249                         return (EDQUOT);
  250                 }
  251         }
  252         return (0);
  253 }
  254 
  255 /*
  256  * Check the inode limit, applying corrective action.
  257  */
  258 int
  259 hfs_chkiq(cp, change, cred, flags)
  260         register struct cnode *cp;
  261         long change;
  262         struct ucred *cred;
  263         int flags;
  264 {
  265         register struct dquot *dq;
  266         register int i;
  267         int ncurinodes, error=0;
  268         struct proc *p;
  269 
  270 #if DIAGNOSTIC
  271         if ((flags & CHOWN) == 0)
  272                 hfs_chkdquot(cp);
  273 #endif
  274         if (change == 0)
  275                 return (0);
  276         if (change < 0) {
  277                 for (i = 0; i < MAXQUOTAS; i++) {
  278                         if ((dq = cp->c_dquot[i]) == NODQUOT)
  279                                 continue;
  280                         while (dq->dq_flags & DQ_LOCK) {
  281                                 dq->dq_flags |= DQ_WANT;
  282                                 sleep((caddr_t)dq, PINOD+1);
  283                         }
  284                         ncurinodes = dq->dq_curinodes + change;
  285                         if (ncurinodes >= 0)
  286                                 dq->dq_curinodes = ncurinodes;
  287                         else
  288                                 dq->dq_curinodes = 0;
  289                         dq->dq_flags &= ~DQ_INODS;
  290                         dq->dq_flags |= DQ_MOD;
  291                 }
  292                 return (0);
  293         }
  294         p = current_proc();
  295         if (cred == NOCRED)
  296                 cred = kernproc->p_ucred;
  297         if ((cred->cr_uid != 0) || (p->p_flag & P_FORCEQUOTA)) {
  298                 for (i = 0; i < MAXQUOTAS; i++) {
  299                         if ((dq = cp->c_dquot[i]) == NODQUOT)
  300                                 continue;
  301                         error = hfs_chkiqchg(cp, change, cred, i);
  302                         if (error) {
  303                                 break;
  304                         }
  305                 }
  306         }
  307         if ((flags & FORCE) || error == 0) { 
  308                 for (i = 0; i < MAXQUOTAS; i++) {
  309                         if ((dq = cp->c_dquot[i]) == NODQUOT)
  310                                 continue;
  311                         while (dq->dq_flags & DQ_LOCK) {
  312                                 dq->dq_flags |= DQ_WANT;
  313                                 sleep((caddr_t)dq, PINOD+1);
  314                         }
  315                         dq->dq_curinodes += change;
  316                         dq->dq_flags |= DQ_MOD;
  317                 }
  318         }
  319         return (error);
  320 }
  321 
  322 /*
  323  * Check for a valid change to a users allocation.
  324  * Issue an error message if appropriate.
  325  */
  326 int
  327 hfs_chkiqchg(cp, change, cred, type)
  328         struct cnode *cp;
  329         long change;
  330         struct ucred *cred;
  331         int type;
  332 {
  333         register struct dquot *dq = cp->c_dquot[type];
  334         long ncurinodes = dq->dq_curinodes + change;
  335         struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
  336 
  337         /*
  338          * If user would exceed their hard limit, disallow cnode allocation.
  339          */
  340         if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
  341                 if ((dq->dq_flags & DQ_INODS) == 0 &&
  342                     cp->c_uid == cred->cr_uid) {
  343 #if 0
  344                         printf("\n%s: write failed, %s cnode limit reached\n",
  345                             vp->v_mount->mnt_stat.f_mntonname,
  346                             quotatypes[type]);
  347 #endif
  348                         dq->dq_flags |= DQ_INODS;
  349                 }
  350                 return (EDQUOT);
  351         }
  352         /*
  353          * If user is over their soft limit for too long, disallow cnode
  354          * allocation. Reset time limit as they cross their soft limit.
  355          */
  356         if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
  357                 if (dq->dq_curinodes < dq->dq_isoftlimit) {
  358                         dq->dq_itime = time.tv_sec +
  359                             VFSTOHFS(vp->v_mount)->hfs_qfiles[type].qf_itime;
  360 #if 0
  361                         if (cp->c_uid == cred->cr_uid)
  362                                 printf("\n%s: warning, %s %s\n",
  363                                     vp->v_mount->mnt_stat.f_mntonname,
  364                                     quotatypes[type], "cnode quota exceeded");
  365 #endif
  366                         return (0);
  367                 }
  368                 if (time.tv_sec > dq->dq_itime) {
  369                         if ((dq->dq_flags & DQ_INODS) == 0 &&
  370                             cp->c_uid == cred->cr_uid) {
  371 #if 0
  372                                 printf("\n%s: write failed, %s %s\n",
  373                                     vp->v_mount->mnt_stat.f_mntonname,
  374                                     quotatypes[type],
  375                                     "cnode quota exceeded for too long");
  376 #endif
  377                                 dq->dq_flags |= DQ_INODS;
  378                         }
  379                         return (EDQUOT);
  380                 }
  381         }
  382         return (0);
  383 }
  384 
  385 #if DIAGNOSTIC
  386 /*
  387  * On filesystems with quotas enabled, it is an error for a file to change
  388  * size and not to have a dquot structure associated with it.
  389  */
  390 void
  391 hfs_chkdquot(cp)
  392         register struct cnode *cp;
  393 {
  394         struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
  395         struct hfsmount *hfsmp = VFSTOHFS(vp->v_mount);
  396         register int i;
  397 
  398         for (i = 0; i < MAXQUOTAS; i++) {
  399                 if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP ||
  400                     (hfsmp->hfs_qfiles[i].qf_qflags & (QTF_OPENING|QTF_CLOSING)))
  401                         continue;
  402                 if (cp->c_dquot[i] == NODQUOT) {
  403                         vprint("chkdquot: missing dquot", vp);
  404                         panic("missing dquot");
  405                 }
  406         }
  407 }
  408 #endif
  409 
  410 /*
  411  * Code to process quotactl commands.
  412  */
  413 
  414 /*
  415  * Q_QUOTAON - set up a quota file for a particular file system.
  416  */
  417 int
  418 hfs_quotaon(p, mp, type, fname, segflg)
  419         struct proc *p;
  420         struct mount *mp;
  421         register int type;
  422         caddr_t fname;
  423         enum uio_seg segflg;
  424 {
  425         struct hfsmount *hfsmp = VFSTOHFS(mp);
  426         struct vnode *vp, **vpp;
  427         struct vnode *nextvp;
  428         struct dquot *dq;
  429         int error;
  430         struct nameidata nd;
  431 
  432         vpp = &hfsmp->hfs_qfiles[type].qf_vp;
  433         NDINIT(&nd, LOOKUP, FOLLOW, segflg, fname, p);
  434         if (error = vn_open(&nd, FREAD|FWRITE, 0))
  435                 return (error);
  436         vp = nd.ni_vp;
  437         VOP_UNLOCK(vp, 0, p);
  438         if (vp->v_type != VREG) {
  439                 (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
  440                 return (EACCES);
  441         }
  442         if (*vpp != vp)
  443                 hfs_quotaoff(p, mp, type);
  444         hfsmp->hfs_qfiles[type].qf_qflags |= QTF_OPENING;
  445         mp->mnt_flag |= MNT_QUOTA;
  446         vp->v_flag |= VNOFLUSH;
  447         *vpp = vp;
  448         /*
  449          * Save the credential of the process that turned on quotas.
  450          */
  451         crhold(p->p_ucred);
  452         hfsmp->hfs_qfiles[type].qf_cred = p->p_ucred;
  453         /* Finish initializing the quota file */
  454         if (error = dqfileopen(&hfsmp->hfs_qfiles[type], type))
  455                 goto exit;
  456         /*
  457          * Search vnodes associated with this mount point,
  458          * adding references to quota file being opened.
  459          * NB: only need to add dquot's for cnodes being modified.
  460          */
  461 again:
  462         for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {
  463                 nextvp = vp->v_mntvnodes.le_next;
  464                 if (vp->v_writecount == 0)
  465                         continue;
  466                 if (vget(vp, LK_EXCLUSIVE, p))
  467                         goto again;
  468                 if (error = hfs_getinoquota(VTOC(vp))) {
  469                         vput(vp);
  470                         break;
  471                 }
  472                 vput(vp);
  473                 if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp)
  474                         goto again;
  475         }
  476 exit:
  477         hfsmp->hfs_qfiles[type].qf_qflags &= ~QTF_OPENING;
  478         if (error)
  479                 hfs_quotaoff(p, mp, type);
  480         return (error);
  481 }
  482 
  483 /*
  484  * Q_QUOTAOFF - turn off disk quotas for a filesystem.
  485  */
  486 int
  487 hfs_quotaoff(p, mp, type)
  488         struct proc *p;
  489         struct mount *mp;
  490         register int type;
  491 {
  492         struct vnode *vp;
  493         struct vnode *qvp, *nextvp;
  494         struct hfsmount *hfsmp = VFSTOHFS(mp);
  495         struct dquot *dq;
  496         struct cnode *cp;
  497         int error;
  498         struct ucred *cred;
  499         
  500         if ((qvp = hfsmp->hfs_qfiles[type].qf_vp) == NULLVP)
  501                 return (0);
  502         hfsmp->hfs_qfiles[type].qf_qflags |= QTF_CLOSING;
  503 
  504         /*
  505          * Sync out any orpaned dirty dquot entries.
  506          */
  507         dqsync_orphans(&hfsmp->hfs_qfiles[type]);
  508 
  509         /*
  510          * Search vnodes associated with this mount point,
  511          * deleting any references to quota file being closed.
  512          */
  513 again:
  514         for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {
  515                 nextvp = vp->v_mntvnodes.le_next;
  516                 if (vget(vp, LK_EXCLUSIVE, p))
  517                         goto again;
  518                 cp = VTOC(vp);
  519                 dq = cp->c_dquot[type];
  520                 cp->c_dquot[type] = NODQUOT;
  521                 dqrele(vp, dq);
  522                 vput(vp);
  523                 if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp)
  524                         goto again;
  525         }
  526         dqflush(qvp);
  527         /* Finish tearing down the quota file */
  528         dqfileclose(&hfsmp->hfs_qfiles[type], type);
  529         qvp->v_flag &= ~VNOFLUSH;
  530         error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);
  531         hfsmp->hfs_qfiles[type].qf_vp = NULLVP;
  532         cred = hfsmp->hfs_qfiles[type].qf_cred;
  533         if (cred != NOCRED) {
  534                 hfsmp->hfs_qfiles[type].qf_cred = NOCRED;
  535                 crfree(cred);
  536         }
  537         hfsmp->hfs_qfiles[type].qf_qflags &= ~QTF_CLOSING;
  538         for (type = 0; type < MAXQUOTAS; type++)
  539                 if (hfsmp->hfs_qfiles[type].qf_vp != NULLVP)
  540                         break;
  541         if (type == MAXQUOTAS)
  542                 mp->mnt_flag &= ~MNT_QUOTA;
  543         return (error);
  544 }
  545 
  546 /*
  547  * Q_GETQUOTA - return current values in a dqblk structure.
  548  */
  549 int
  550 hfs_getquota(mp, id, type, addr)
  551         struct mount *mp;
  552         u_long id;
  553         int type;
  554         caddr_t addr;
  555 {
  556         struct dquot *dq;
  557         int error;
  558 
  559         if (error = dqget(NULLVP, id, &VFSTOHFS(mp)->hfs_qfiles[type], type, &dq))
  560                 return (error);
  561         error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));
  562         dqrele(NULLVP, dq);
  563         return (error);
  564 }
  565 
  566 /*
  567  * Q_SETQUOTA - assign an entire dqblk structure.
  568  */
  569 int
  570 hfs_setquota(mp, id, type, addr)
  571         struct mount *mp;
  572         u_long id;
  573         int type;
  574         caddr_t addr;
  575 {
  576         register struct dquot *dq;
  577         struct dquot *ndq;
  578         struct hfsmount *hfsmp = VFSTOHFS(mp);
  579         struct dqblk newlim;
  580         int error;
  581 
  582         if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))
  583                 return (error);
  584         if (error = dqget(NULLVP, id, &hfsmp->hfs_qfiles[type], type, &ndq))
  585                 return (error);
  586         dq = ndq;
  587         while (dq->dq_flags & DQ_LOCK) {
  588                 dq->dq_flags |= DQ_WANT;
  589                 sleep((caddr_t)dq, PINOD+1);
  590         }
  591         /*
  592          * Copy all but the current values.
  593          * Reset time limit if previously had no soft limit or were
  594          * under it, but now have a soft limit and are over it.
  595          */
  596         newlim.dqb_curbytes = dq->dq_curbytes;
  597         newlim.dqb_curinodes = dq->dq_curinodes;
  598         if (dq->dq_id != 0) {
  599                 newlim.dqb_btime = dq->dq_btime;
  600                 newlim.dqb_itime = dq->dq_itime;
  601         }
  602         if (newlim.dqb_bsoftlimit &&
  603             dq->dq_curbytes >= newlim.dqb_bsoftlimit &&
  604             (dq->dq_bsoftlimit == 0 || dq->dq_curbytes < dq->dq_bsoftlimit))
  605                 newlim.dqb_btime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_btime;
  606         if (newlim.dqb_isoftlimit &&
  607             dq->dq_curinodes >= newlim.dqb_isoftlimit &&
  608             (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
  609                 newlim.dqb_itime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_itime;
  610         dq->dq_dqb = newlim;
  611         if (dq->dq_curbytes < dq->dq_bsoftlimit)
  612                 dq->dq_flags &= ~DQ_BLKS;
  613         if (dq->dq_curinodes < dq->dq_isoftlimit)
  614                 dq->dq_flags &= ~DQ_INODS;
  615         if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
  616             dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
  617                 dq->dq_flags |= DQ_FAKE;
  618         else
  619                 dq->dq_flags &= ~DQ_FAKE;
  620         dq->dq_flags |= DQ_MOD;
  621         dqrele(NULLVP, dq);
  622         return (0);
  623 }
  624 
  625 /*
  626  * Q_SETUSE - set current cnode and byte usage.
  627  */
  628 int
  629 hfs_setuse(mp, id, type, addr)
  630         struct mount *mp;
  631         u_long id;
  632         int type;
  633         caddr_t addr;
  634 {
  635         register struct dquot *dq;
  636         struct hfsmount *hfsmp = VFSTOHFS(mp);
  637         struct dquot *ndq;
  638         struct dqblk usage;
  639         int error;
  640 
  641         if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))
  642                 return (error);
  643         if (error = dqget(NULLVP, id, &hfsmp->hfs_qfiles[type], type, &ndq))
  644                 return (error);
  645         dq = ndq;
  646         while (dq->dq_flags & DQ_LOCK) {
  647                 dq->dq_flags |= DQ_WANT;
  648                 sleep((caddr_t)dq, PINOD+1);
  649         }
  650         /*
  651          * Reset time limit if have a soft limit and were
  652          * previously under it, but are now over it.
  653          */
  654         if (dq->dq_bsoftlimit && dq->dq_curbytes < dq->dq_bsoftlimit &&
  655             usage.dqb_curbytes >= dq->dq_bsoftlimit)
  656                 dq->dq_btime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_btime;
  657         if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
  658             usage.dqb_curinodes >= dq->dq_isoftlimit)
  659                 dq->dq_itime = time.tv_sec + hfsmp->hfs_qfiles[type].qf_itime;
  660         dq->dq_curbytes = usage.dqb_curbytes;
  661         dq->dq_curinodes = usage.dqb_curinodes;
  662         if (dq->dq_curbytes < dq->dq_bsoftlimit)
  663                 dq->dq_flags &= ~DQ_BLKS;
  664         if (dq->dq_curinodes < dq->dq_isoftlimit)
  665                 dq->dq_flags &= ~DQ_INODS;
  666         dq->dq_flags |= DQ_MOD;
  667         dqrele(NULLVP, dq);
  668         return (0);
  669 }
  670 
  671 /*
  672  * Q_SYNC - sync quota files to disk.
  673  */
  674 int
  675 hfs_qsync(mp)
  676         struct mount *mp;
  677 {
  678         struct hfsmount *hfsmp = VFSTOHFS(mp);
  679         struct proc *p = current_proc();                /* XXX */
  680         struct vnode *vp, *nextvp;
  681         struct dquot *dq;
  682         int i, error;
  683 
  684         /*
  685          * Check if the mount point has any quotas.
  686          * If not, simply return.
  687          */
  688         for (i = 0; i < MAXQUOTAS; i++)
  689                 if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP)
  690                         break;
  691         if (i == MAXQUOTAS)
  692                 return (0);
  693 
  694         /*
  695          * Sync out any orpaned dirty dquot entries.
  696          */
  697         for (i = 0; i < MAXQUOTAS; i++)
  698                 if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP)
  699                         dqsync_orphans(&hfsmp->hfs_qfiles[i]);
  700 
  701         /*
  702          * Search vnodes associated with this mount point,
  703          * synchronizing any modified dquot structures.
  704          */
  705         simple_lock(&mntvnode_slock);
  706 again:
  707         for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {
  708                 if (vp->v_mount != mp)
  709                         goto again;
  710                 nextvp = vp->v_mntvnodes.le_next;
  711                 simple_lock(&vp->v_interlock);
  712                 simple_unlock(&mntvnode_slock);
  713                 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
  714                 if (error) {
  715                         simple_lock(&mntvnode_slock);
  716                         if (error == ENOENT)
  717                                 goto again;
  718                         continue;
  719                 }
  720 
  721                 /* Make sure that this is really an hfs vnode. */
  722                 if (vp->v_mount != mp   ||
  723                     vp->v_type == VNON  ||
  724                     vp->v_tag != VT_HFS ||
  725                     VTOC(vp) == NULL) {
  726                         vput(vp);
  727                         simple_lock(&mntvnode_slock);
  728                         goto again;
  729                 }
  730 
  731                 for (i = 0; i < MAXQUOTAS; i++) {
  732                         dq = VTOC(vp)->c_dquot[i];
  733                         if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
  734                                 dqsync(vp, dq);
  735                 }
  736                 vput(vp);
  737                 simple_lock(&mntvnode_slock);
  738                 if (vp->v_mntvnodes.le_next != nextvp)
  739                         goto again;
  740         }
  741         simple_unlock(&mntvnode_slock);
  742         return (0);
  743 }
  744 
  745 /*
  746  * Q_QUOTASTAT - get quota on/off status 
  747  */
  748 int
  749 hfs_quotastat(mp, type, addr)
  750         struct mount *mp;
  751         register int type;
  752         caddr_t addr;
  753 {
  754         struct hfsmount *hfsmp = VFSTOHFS(mp);
  755         int error = 0;
  756         int qstat;
  757 
  758         if ((mp->mnt_flag & MNT_QUOTA) && (hfsmp->hfs_qfiles[type].qf_vp != NULLVP))
  759           qstat = 1;   /* quotas are on for this type */
  760         else
  761           qstat = 0;   /* quotas are off for this type */
  762         
  763         error = copyout ((caddr_t)&qstat, addr, sizeof(qstat));
  764         return (error);
  765 }
  766 

Cache object: 987b37302bf2fa700f805387fd1e7392


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.