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/ufs/ufs/ufs_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) 1982, 1986, 1990, 1993, 1995
    3  *      The Regents of the University of California.  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  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD$");
   37 
   38 #include "opt_ffs.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/endian.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mount.h>
   48 #include <sys/mutex.h>
   49 #include <sys/namei.h>
   50 #include <sys/priv.h>
   51 #include <sys/proc.h>
   52 #include <sys/socket.h>
   53 #include <sys/stat.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/vnode.h>
   56 
   57 #include <ufs/ufs/extattr.h>
   58 #include <ufs/ufs/quota.h>
   59 #include <ufs/ufs/inode.h>
   60 #include <ufs/ufs/ufsmount.h>
   61 #include <ufs/ufs/ufs_extern.h>
   62 
   63 CTASSERT(sizeof(struct dqblk64) == sizeof(struct dqhdr64));
   64 
   65 static int unprivileged_get_quota = 0;
   66 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_get_quota, CTLFLAG_RW,
   67     &unprivileged_get_quota, 0,
   68     "Unprivileged processes may retrieve quotas for other uids and gids");
   69 
   70 static MALLOC_DEFINE(M_DQUOT, "ufs_quota", "UFS quota entries");
   71 
   72 /*
   73  * Quota name to error message mapping.
   74  */
   75 static char *quotatypes[] = INITQFNAMES;
   76 
   77 static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int, int *);
   78 static int chkiqchg(struct inode *, int, struct ucred *, int, int *);
   79 static int dqopen(struct vnode *, struct ufsmount *, int);
   80 static int dqget(struct vnode *,
   81         u_long, struct ufsmount *, int, struct dquot **);
   82 static int dqsync(struct vnode *, struct dquot *);
   83 static int dqflush(struct vnode *);
   84 static int quotaoff1(struct thread *td, struct mount *mp, int type);
   85 static int quotaoff_inchange(struct thread *td, struct mount *mp, int type);
   86 
   87 /* conversion functions - from_to() */
   88 static void dqb32_dq(const struct dqblk32 *, struct dquot *);
   89 static void dqb64_dq(const struct dqblk64 *, struct dquot *);
   90 static void dq_dqb32(const struct dquot *, struct dqblk32 *);
   91 static void dq_dqb64(const struct dquot *, struct dqblk64 *);
   92 static void dqb32_dqb64(const struct dqblk32 *, struct dqblk64 *);
   93 static void dqb64_dqb32(const struct dqblk64 *, struct dqblk32 *);
   94 
   95 #ifdef DIAGNOSTIC
   96 static void dqref(struct dquot *);
   97 static void chkdquot(struct inode *);
   98 #endif
   99 
  100 /*
  101  * Set up the quotas for an inode.
  102  *
  103  * This routine completely defines the semantics of quotas.
  104  * If other criterion want to be used to establish quotas, the
  105  * MAXQUOTAS value in quota.h should be increased, and the
  106  * additional dquots set up here.
  107  */
  108 int
  109 getinoquota(struct inode *ip)
  110 {
  111         struct ufsmount *ump;
  112         struct vnode *vp;
  113         int error;
  114 
  115         vp = ITOV(ip);
  116 
  117         /*
  118          * Disk quotas must be turned off for system files.  Currently
  119          * snapshot and quota files.
  120          */
  121         if ((vp->v_vflag & VV_SYSTEM) != 0)
  122                 return (0);
  123         /*
  124          * XXX: Turn off quotas for files with a negative UID or GID.
  125          * This prevents the creation of 100GB+ quota files.
  126          */
  127         if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
  128                 return (0);
  129         ump = VFSTOUFS(vp->v_mount);
  130         /*
  131          * Set up the user quota based on file uid.
  132          * EINVAL means that quotas are not enabled.
  133          */
  134         if ((error =
  135                 dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
  136             error != EINVAL)
  137                 return (error);
  138         /*
  139          * Set up the group quota based on file gid.
  140          * EINVAL means that quotas are not enabled.
  141          */
  142         if ((error =
  143                 dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
  144             error != EINVAL)
  145                 return (error);
  146         return (0);
  147 }
  148 
  149 /*
  150  * Update disk usage, and take corrective action.
  151  */
  152 int
  153 chkdq(struct inode *ip, ufs2_daddr_t change, struct ucred *cred, int flags)
  154 {
  155         struct dquot *dq;
  156         ufs2_daddr_t ncurblocks;
  157         struct vnode *vp = ITOV(ip);
  158         int i, error, warn, do_check;
  159 
  160         /*
  161          * Disk quotas must be turned off for system files.  Currently
  162          * snapshot and quota files.
  163          */
  164         if ((vp->v_vflag & VV_SYSTEM) != 0)
  165                 return (0);
  166         /*
  167          * XXX: Turn off quotas for files with a negative UID or GID.
  168          * This prevents the creation of 100GB+ quota files.
  169          */
  170         if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
  171                 return (0);
  172 #ifdef DIAGNOSTIC
  173         if ((flags & CHOWN) == 0)
  174                 chkdquot(ip);
  175 #endif
  176         if (change == 0)
  177                 return (0);
  178         if (change < 0) {
  179                 for (i = 0; i < MAXQUOTAS; i++) {
  180                         if ((dq = ip->i_dquot[i]) == NODQUOT)
  181                                 continue;
  182                         DQI_LOCK(dq);
  183                         DQI_WAIT(dq, PINOD+1, "chkdq1");
  184                         ncurblocks = dq->dq_curblocks + change;
  185                         if (ncurblocks >= 0)
  186                                 dq->dq_curblocks = ncurblocks;
  187                         else
  188                                 dq->dq_curblocks = 0;
  189                         dq->dq_flags &= ~DQ_BLKS;
  190                         dq->dq_flags |= DQ_MOD;
  191                         DQI_UNLOCK(dq);
  192                 }
  193                 return (0);
  194         }
  195         if ((flags & FORCE) == 0 &&
  196             priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
  197                 do_check = 1;
  198         else
  199                 do_check = 0;
  200         for (i = 0; i < MAXQUOTAS; i++) {
  201                 if ((dq = ip->i_dquot[i]) == NODQUOT)
  202                         continue;
  203                 warn = 0;
  204                 DQI_LOCK(dq);
  205                 DQI_WAIT(dq, PINOD+1, "chkdq2");
  206                 if (do_check) {
  207                         error = chkdqchg(ip, change, cred, i, &warn);
  208                         if (error) {
  209                                 /*
  210                                  * Roll back user quota changes when
  211                                  * group quota failed.
  212                                  */
  213                                 while (i > 0) {
  214                                         --i;
  215                                         dq = ip->i_dquot[i];
  216                                         if (dq == NODQUOT)
  217                                                 continue;
  218                                         DQI_LOCK(dq);
  219                                         DQI_WAIT(dq, PINOD+1, "chkdq3");
  220                                         ncurblocks = dq->dq_curblocks - change;
  221                                         if (ncurblocks >= 0)
  222                                                 dq->dq_curblocks = ncurblocks;
  223                                         else
  224                                                 dq->dq_curblocks = 0;
  225                                         dq->dq_flags &= ~DQ_BLKS;
  226                                         dq->dq_flags |= DQ_MOD;
  227                                         DQI_UNLOCK(dq);
  228                                 }
  229                                 return (error);
  230                         }
  231                 }
  232                 /* Reset timer when crossing soft limit */
  233                 if (dq->dq_curblocks + change >= dq->dq_bsoftlimit &&
  234                     dq->dq_curblocks < dq->dq_bsoftlimit)
  235                         dq->dq_btime = time_second + ip->i_ump->um_btime[i];
  236                 dq->dq_curblocks += change;
  237                 dq->dq_flags |= DQ_MOD;
  238                 DQI_UNLOCK(dq);
  239                 if (warn)
  240                         uprintf("\n%s: warning, %s disk quota exceeded\n",
  241                             ITOV(ip)->v_mount->mnt_stat.f_mntonname,
  242                             quotatypes[i]);
  243         }
  244         return (0);
  245 }
  246 
  247 /*
  248  * Check for a valid change to a users allocation.
  249  * Issue an error message if appropriate.
  250  */
  251 static int
  252 chkdqchg(struct inode *ip, ufs2_daddr_t change, struct ucred *cred,
  253     int type, int *warn)
  254 {
  255         struct dquot *dq = ip->i_dquot[type];
  256         ufs2_daddr_t ncurblocks = dq->dq_curblocks + change;
  257 
  258         /*
  259          * If user would exceed their hard limit, disallow space allocation.
  260          */
  261         if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
  262                 if ((dq->dq_flags & DQ_BLKS) == 0 &&
  263                     ip->i_uid == cred->cr_uid) {
  264                         dq->dq_flags |= DQ_BLKS;
  265                         DQI_UNLOCK(dq);
  266                         uprintf("\n%s: write failed, %s disk limit reached\n",
  267                             ITOV(ip)->v_mount->mnt_stat.f_mntonname,
  268                             quotatypes[type]);
  269                         return (EDQUOT);
  270                 }
  271                 DQI_UNLOCK(dq);
  272                 return (EDQUOT);
  273         }
  274         /*
  275          * If user is over their soft limit for too long, disallow space
  276          * allocation. Reset time limit as they cross their soft limit.
  277          */
  278         if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
  279                 if (dq->dq_curblocks < dq->dq_bsoftlimit) {
  280                         dq->dq_btime = time_second + ip->i_ump->um_btime[type];
  281                         if (ip->i_uid == cred->cr_uid)
  282                                 *warn = 1;
  283                         return (0);
  284                 }
  285                 if (time_second > dq->dq_btime) {
  286                         if ((dq->dq_flags & DQ_BLKS) == 0 &&
  287                             ip->i_uid == cred->cr_uid) {
  288                                 dq->dq_flags |= DQ_BLKS;
  289                                 DQI_UNLOCK(dq);
  290                                 uprintf("\n%s: write failed, %s "
  291                                     "disk quota exceeded for too long\n",
  292                                     ITOV(ip)->v_mount->mnt_stat.f_mntonname,
  293                                     quotatypes[type]);
  294                                 return (EDQUOT);
  295                         }
  296                         DQI_UNLOCK(dq);
  297                         return (EDQUOT);
  298                 }
  299         }
  300         return (0);
  301 }
  302 
  303 /*
  304  * Check the inode limit, applying corrective action.
  305  */
  306 int
  307 chkiq(struct inode *ip, int change, struct ucred *cred, int flags)
  308 {
  309         struct dquot *dq;
  310         ino_t ncurinodes;
  311         int i, error, warn, do_check;
  312 
  313 #ifdef DIAGNOSTIC
  314         if ((flags & CHOWN) == 0)
  315                 chkdquot(ip);
  316 #endif
  317         if (change == 0)
  318                 return (0);
  319         if (change < 0) {
  320                 for (i = 0; i < MAXQUOTAS; i++) {
  321                         if ((dq = ip->i_dquot[i]) == NODQUOT)
  322                                 continue;
  323                         DQI_LOCK(dq);
  324                         DQI_WAIT(dq, PINOD+1, "chkiq1");
  325                         ncurinodes = dq->dq_curinodes + change;
  326                         /* XXX: ncurinodes is unsigned */
  327                         if (dq->dq_curinodes != 0 && ncurinodes >= 0)
  328                                 dq->dq_curinodes = ncurinodes;
  329                         else
  330                                 dq->dq_curinodes = 0;
  331                         dq->dq_flags &= ~DQ_INODS;
  332                         dq->dq_flags |= DQ_MOD;
  333                         DQI_UNLOCK(dq);
  334                 }
  335                 return (0);
  336         }
  337         if ((flags & FORCE) == 0 &&
  338             priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
  339                 do_check = 1;
  340         else
  341                 do_check = 0;
  342         for (i = 0; i < MAXQUOTAS; i++) {
  343                 if ((dq = ip->i_dquot[i]) == NODQUOT)
  344                         continue;
  345                 warn = 0;
  346                 DQI_LOCK(dq);
  347                 DQI_WAIT(dq, PINOD+1, "chkiq2");
  348                 if (do_check) {
  349                         error = chkiqchg(ip, change, cred, i, &warn);
  350                         if (error) {
  351                                 /*
  352                                  * Roll back user quota changes when
  353                                  * group quota failed.
  354                                  */
  355                                 while (i > 0) {
  356                                         --i;
  357                                         dq = ip->i_dquot[i];
  358                                         if (dq == NODQUOT)
  359                                                 continue;
  360                                         DQI_LOCK(dq);
  361                                         DQI_WAIT(dq, PINOD+1, "chkiq3");
  362                                         ncurinodes = dq->dq_curinodes - change;
  363                                         /* XXX: ncurinodes is unsigned */
  364                                         if (dq->dq_curinodes != 0 &&
  365                                             ncurinodes >= 0)
  366                                                 dq->dq_curinodes = ncurinodes;
  367                                         else
  368                                                 dq->dq_curinodes = 0;
  369                                         dq->dq_flags &= ~DQ_INODS;
  370                                         dq->dq_flags |= DQ_MOD;
  371                                         DQI_UNLOCK(dq);
  372                                 }
  373                                 return (error);
  374                         }
  375                 }
  376                 /* Reset timer when crossing soft limit */
  377                 if (dq->dq_curinodes + change >= dq->dq_isoftlimit &&
  378                     dq->dq_curinodes < dq->dq_isoftlimit)
  379                         dq->dq_itime = time_second + ip->i_ump->um_itime[i];
  380                 dq->dq_curinodes += change;
  381                 dq->dq_flags |= DQ_MOD;
  382                 DQI_UNLOCK(dq);
  383                 if (warn)
  384                         uprintf("\n%s: warning, %s inode quota exceeded\n",
  385                             ITOV(ip)->v_mount->mnt_stat.f_mntonname,
  386                             quotatypes[i]);
  387         }
  388         return (0);
  389 }
  390 
  391 /*
  392  * Check for a valid change to a users allocation.
  393  * Issue an error message if appropriate.
  394  */
  395 static int
  396 chkiqchg(struct inode *ip, int change, struct ucred *cred, int type, int *warn)
  397 {
  398         struct dquot *dq = ip->i_dquot[type];
  399         ino_t ncurinodes = dq->dq_curinodes + change;
  400 
  401         /*
  402          * If user would exceed their hard limit, disallow inode allocation.
  403          */
  404         if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
  405                 if ((dq->dq_flags & DQ_INODS) == 0 &&
  406                     ip->i_uid == cred->cr_uid) {
  407                         dq->dq_flags |= DQ_INODS;
  408                         DQI_UNLOCK(dq);
  409                         uprintf("\n%s: write failed, %s inode limit reached\n",
  410                             ITOV(ip)->v_mount->mnt_stat.f_mntonname,
  411                             quotatypes[type]);
  412                         return (EDQUOT);
  413                 }
  414                 DQI_UNLOCK(dq);
  415                 return (EDQUOT);
  416         }
  417         /*
  418          * If user is over their soft limit for too long, disallow inode
  419          * allocation. Reset time limit as they cross their soft limit.
  420          */
  421         if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
  422                 if (dq->dq_curinodes < dq->dq_isoftlimit) {
  423                         dq->dq_itime = time_second + ip->i_ump->um_itime[type];
  424                         if (ip->i_uid == cred->cr_uid)
  425                                 *warn = 1;
  426                         return (0);
  427                 }
  428                 if (time_second > dq->dq_itime) {
  429                         if ((dq->dq_flags & DQ_INODS) == 0 &&
  430                             ip->i_uid == cred->cr_uid) {
  431                                 dq->dq_flags |= DQ_INODS;
  432                                 DQI_UNLOCK(dq);
  433                                 uprintf("\n%s: write failed, %s "
  434                                     "inode quota exceeded for too long\n",
  435                                     ITOV(ip)->v_mount->mnt_stat.f_mntonname,
  436                                     quotatypes[type]);
  437                                 return (EDQUOT);
  438                         }
  439                         DQI_UNLOCK(dq);
  440                         return (EDQUOT);
  441                 }
  442         }
  443         return (0);
  444 }
  445 
  446 #ifdef DIAGNOSTIC
  447 /*
  448  * On filesystems with quotas enabled, it is an error for a file to change
  449  * size and not to have a dquot structure associated with it.
  450  */
  451 static void
  452 chkdquot(struct inode *ip)
  453 {
  454         struct ufsmount *ump = ip->i_ump;
  455         struct vnode *vp = ITOV(ip);
  456         int i;
  457 
  458         /*
  459          * Disk quotas must be turned off for system files.  Currently
  460          * these are snapshots and quota files.
  461          */
  462         if ((vp->v_vflag & VV_SYSTEM) != 0)
  463                 return;
  464         /*
  465          * XXX: Turn off quotas for files with a negative UID or GID.
  466          * This prevents the creation of 100GB+ quota files.
  467          */
  468         if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
  469                 return;
  470 
  471         UFS_LOCK(ump);
  472         for (i = 0; i < MAXQUOTAS; i++) {
  473                 if (ump->um_quotas[i] == NULLVP ||
  474                     (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
  475                         continue;
  476                 if (ip->i_dquot[i] == NODQUOT) {
  477                         UFS_UNLOCK(ump);
  478                         vprint("chkdquot: missing dquot", ITOV(ip));
  479                         panic("chkdquot: missing dquot");
  480                 }
  481         }
  482         UFS_UNLOCK(ump);
  483 }
  484 #endif
  485 
  486 /*
  487  * Code to process quotactl commands.
  488  */
  489 
  490 /*
  491  * Q_QUOTAON - set up a quota file for a particular filesystem.
  492  */
  493 int
  494 quotaon(struct thread *td, struct mount *mp, int type, void *fname)
  495 {
  496         struct ufsmount *ump;
  497         struct vnode *vp, **vpp;
  498         struct vnode *mvp;
  499         struct dquot *dq;
  500         int error, flags, vfslocked;
  501         struct nameidata nd;
  502 
  503         error = priv_check(td, PRIV_UFS_QUOTAON);
  504         if (error)
  505                 return (error);
  506 
  507         if (mp->mnt_flag & MNT_RDONLY)
  508                 return (EROFS);
  509 
  510         ump = VFSTOUFS(mp);
  511         dq = NODQUOT;
  512 
  513         NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_USERSPACE, fname, td);
  514         flags = FREAD | FWRITE;
  515         vfs_ref(mp);
  516         vfs_unbusy(mp);
  517         error = vn_open(&nd, &flags, 0, NULL);
  518         if (error != 0) {
  519                 vfs_rel(mp);
  520                 return (error);
  521         }
  522         vfslocked = NDHASGIANT(&nd);
  523         NDFREE(&nd, NDF_ONLY_PNBUF);
  524         vp = nd.ni_vp;
  525         error = vfs_busy(mp, MBF_NOWAIT);
  526         vfs_rel(mp);
  527         if (error == 0) {
  528                 if (vp->v_type != VREG) {
  529                         error = EACCES;
  530                         vfs_unbusy(mp);
  531                 }
  532         }
  533         if (error != 0) {
  534                 VOP_UNLOCK(vp, 0);
  535                 (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
  536                 VFS_UNLOCK_GIANT(vfslocked);
  537                 return (error);
  538         }
  539 
  540         UFS_LOCK(ump);
  541         if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) {
  542                 UFS_UNLOCK(ump);
  543                 VOP_UNLOCK(vp, 0);
  544                 (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
  545                 VFS_UNLOCK_GIANT(vfslocked);
  546                 vfs_unbusy(mp);
  547                 return (EALREADY);
  548         }
  549         ump->um_qflags[type] |= QTF_OPENING|QTF_CLOSING;
  550         UFS_UNLOCK(ump);
  551         if ((error = dqopen(vp, ump, type)) != 0) {
  552                 VOP_UNLOCK(vp, 0);
  553                 UFS_LOCK(ump);
  554                 ump->um_qflags[type] &= ~(QTF_OPENING|QTF_CLOSING);
  555                 UFS_UNLOCK(ump);
  556                 (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
  557                 VFS_UNLOCK_GIANT(vfslocked);
  558                 vfs_unbusy(mp);
  559                 return (error);
  560         }
  561         VOP_UNLOCK(vp, 0);
  562         MNT_ILOCK(mp);
  563         mp->mnt_flag |= MNT_QUOTA;
  564         MNT_IUNLOCK(mp);
  565 
  566         vpp = &ump->um_quotas[type];
  567         if (*vpp != vp)
  568                 quotaoff1(td, mp, type);
  569 
  570         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  571         vp->v_vflag |= VV_SYSTEM;
  572         VOP_UNLOCK(vp, 0);
  573         *vpp = vp;
  574         VFS_UNLOCK_GIANT(vfslocked);
  575         /*
  576          * Save the credential of the process that turned on quotas.
  577          * Set up the time limits for this quota.
  578          */
  579         ump->um_cred[type] = crhold(td->td_ucred);
  580         ump->um_btime[type] = MAX_DQ_TIME;
  581         ump->um_itime[type] = MAX_IQ_TIME;
  582         if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
  583                 if (dq->dq_btime > 0)
  584                         ump->um_btime[type] = dq->dq_btime;
  585                 if (dq->dq_itime > 0)
  586                         ump->um_itime[type] = dq->dq_itime;
  587                 dqrele(NULLVP, dq);
  588         }
  589         /*
  590          * Allow the getdq from getinoquota below to read the quota
  591          * from file.
  592          */
  593         UFS_LOCK(ump);
  594         ump->um_qflags[type] &= ~QTF_CLOSING;
  595         UFS_UNLOCK(ump);
  596         /*
  597          * Search vnodes associated with this mount point,
  598          * adding references to quota file being opened.
  599          * NB: only need to add dquot's for inodes being modified.
  600          */
  601 again:
  602         MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
  603                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
  604                         MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
  605                         goto again;
  606                 }
  607                 if (vp->v_type == VNON || vp->v_writecount == 0) {
  608                         VOP_UNLOCK(vp, 0);
  609                         vrele(vp);
  610                         continue;
  611                 }
  612                 error = getinoquota(VTOI(vp));
  613                 VOP_UNLOCK(vp, 0);
  614                 vrele(vp);
  615                 if (error) {
  616                         MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
  617                         break;
  618                 }
  619         }
  620 
  621         if (error)
  622                 quotaoff_inchange(td, mp, type);
  623         UFS_LOCK(ump);
  624         ump->um_qflags[type] &= ~QTF_OPENING;
  625         KASSERT((ump->um_qflags[type] & QTF_CLOSING) == 0,
  626                 ("quotaon: leaking flags"));
  627         UFS_UNLOCK(ump);
  628 
  629         vfs_unbusy(mp);
  630         return (error);
  631 }
  632 
  633 /*
  634  * Main code to turn off disk quotas for a filesystem. Does not change
  635  * flags.
  636  */
  637 static int
  638 quotaoff1(struct thread *td, struct mount *mp, int type)
  639 {
  640         struct vnode *vp;
  641         struct vnode *qvp, *mvp;
  642         struct ufsmount *ump;
  643         struct dquot *dq;
  644         struct inode *ip;
  645         struct ucred *cr;
  646         int vfslocked;
  647         int error;
  648 
  649         ump = VFSTOUFS(mp);
  650 
  651         UFS_LOCK(ump);
  652         KASSERT((ump->um_qflags[type] & QTF_CLOSING) != 0,
  653                 ("quotaoff1: flags are invalid"));
  654         if ((qvp = ump->um_quotas[type]) == NULLVP) {
  655                 UFS_UNLOCK(ump);
  656                 return (0);
  657         }
  658         cr = ump->um_cred[type];
  659         UFS_UNLOCK(ump);
  660 
  661         /*
  662          * Search vnodes associated with this mount point,
  663          * deleting any references to quota file being closed.
  664          */
  665 again:
  666         MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
  667                 if (vp->v_type == VNON) {
  668                         VI_UNLOCK(vp);
  669                         continue;
  670                 }
  671                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
  672                         MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
  673                         goto again;
  674                 }
  675                 ip = VTOI(vp);
  676                 dq = ip->i_dquot[type];
  677                 ip->i_dquot[type] = NODQUOT;
  678                 dqrele(vp, dq);
  679                 VOP_UNLOCK(vp, 0);
  680                 vrele(vp);
  681         }
  682 
  683         error = dqflush(qvp);
  684         if (error != 0)
  685                 return (error);
  686 
  687         /*
  688          * Clear um_quotas before closing the quota vnode to prevent
  689          * access to the closed vnode from dqget/dqsync
  690          */
  691         UFS_LOCK(ump);
  692         ump->um_quotas[type] = NULLVP;
  693         ump->um_cred[type] = NOCRED;
  694         UFS_UNLOCK(ump);
  695 
  696         vfslocked = VFS_LOCK_GIANT(qvp->v_mount);
  697         vn_lock(qvp, LK_EXCLUSIVE | LK_RETRY);
  698         qvp->v_vflag &= ~VV_SYSTEM;
  699         VOP_UNLOCK(qvp, 0);
  700         error = vn_close(qvp, FREAD|FWRITE, td->td_ucred, td);
  701         VFS_UNLOCK_GIANT(vfslocked);
  702         crfree(cr);
  703 
  704         return (error);
  705 }
  706 
  707 /*
  708  * Turns off quotas, assumes that ump->um_qflags are already checked
  709  * and QTF_CLOSING is set to indicate operation in progress. Fixes
  710  * ump->um_qflags and mp->mnt_flag after.
  711  */
  712 int
  713 quotaoff_inchange(struct thread *td, struct mount *mp, int type)
  714 {
  715         struct ufsmount *ump;
  716         int i;
  717         int error;
  718 
  719         error = quotaoff1(td, mp, type);
  720 
  721         ump = VFSTOUFS(mp);
  722         UFS_LOCK(ump);
  723         ump->um_qflags[type] &= ~QTF_CLOSING;
  724         for (i = 0; i < MAXQUOTAS; i++)
  725                 if (ump->um_quotas[i] != NULLVP)
  726                         break;
  727         if (i == MAXQUOTAS) {
  728                 MNT_ILOCK(mp);
  729                 mp->mnt_flag &= ~MNT_QUOTA;
  730                 MNT_IUNLOCK(mp);
  731         }
  732         UFS_UNLOCK(ump);
  733         return (error);
  734 }
  735 
  736 /*
  737  * Q_QUOTAOFF - turn off disk quotas for a filesystem.
  738  */
  739 int
  740 quotaoff(struct thread *td, struct mount *mp, int type)
  741 {
  742         struct ufsmount *ump;
  743         int error;
  744 
  745         error = priv_check(td, PRIV_UFS_QUOTAOFF);
  746         if (error)
  747                 return (error);
  748 
  749         ump = VFSTOUFS(mp);
  750         UFS_LOCK(ump);
  751         if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) {
  752                 UFS_UNLOCK(ump);
  753                 return (EALREADY);
  754         }
  755         ump->um_qflags[type] |= QTF_CLOSING;
  756         UFS_UNLOCK(ump);
  757 
  758         return (quotaoff_inchange(td, mp, type));
  759 }
  760 
  761 /*
  762  * Q_GETQUOTA - return current values in a dqblk structure.
  763  */
  764 static int
  765 _getquota(struct thread *td, struct mount *mp, u_long id, int type,
  766     struct dqblk64 *dqb)
  767 {
  768         struct dquot *dq;
  769         int error;
  770 
  771         switch (type) {
  772         case USRQUOTA:
  773                 if ((td->td_ucred->cr_uid != id) && !unprivileged_get_quota) {
  774                         error = priv_check(td, PRIV_VFS_GETQUOTA);
  775                         if (error)
  776                                 return (error);
  777                 }
  778                 break;
  779 
  780         case GRPQUOTA:
  781                 if (!groupmember(id, td->td_ucred) &&
  782                     !unprivileged_get_quota) {
  783                         error = priv_check(td, PRIV_VFS_GETQUOTA);
  784                         if (error)
  785                                 return (error);
  786                 }
  787                 break;
  788 
  789         default:
  790                 return (EINVAL);
  791         }
  792 
  793         dq = NODQUOT;
  794         error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq);
  795         if (error)
  796                 return (error);
  797         *dqb = dq->dq_dqb;
  798         dqrele(NULLVP, dq);
  799         return (error);
  800 }
  801 
  802 /*
  803  * Q_SETQUOTA - assign an entire dqblk structure.
  804  */
  805 static int
  806 _setquota(struct thread *td, struct mount *mp, u_long id, int type,
  807     struct dqblk64 *dqb)
  808 {
  809         struct dquot *dq;
  810         struct dquot *ndq;
  811         struct ufsmount *ump;
  812         struct dqblk64 newlim;
  813         int error;
  814 
  815         error = priv_check(td, PRIV_VFS_SETQUOTA);
  816         if (error)
  817                 return (error);
  818 
  819         newlim = *dqb;
  820 
  821         ndq = NODQUOT;
  822         ump = VFSTOUFS(mp);
  823 
  824         error = dqget(NULLVP, id, ump, type, &ndq);
  825         if (error)
  826                 return (error);
  827         dq = ndq;
  828         DQI_LOCK(dq);
  829         DQI_WAIT(dq, PINOD+1, "setqta");
  830         /*
  831          * Copy all but the current values.
  832          * Reset time limit if previously had no soft limit or were
  833          * under it, but now have a soft limit and are over it.
  834          */
  835         newlim.dqb_curblocks = dq->dq_curblocks;
  836         newlim.dqb_curinodes = dq->dq_curinodes;
  837         if (dq->dq_id != 0) {
  838                 newlim.dqb_btime = dq->dq_btime;
  839                 newlim.dqb_itime = dq->dq_itime;
  840         }
  841         if (newlim.dqb_bsoftlimit &&
  842             dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
  843             (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
  844                 newlim.dqb_btime = time_second + ump->um_btime[type];
  845         if (newlim.dqb_isoftlimit &&
  846             dq->dq_curinodes >= newlim.dqb_isoftlimit &&
  847             (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
  848                 newlim.dqb_itime = time_second + ump->um_itime[type];
  849         dq->dq_dqb = newlim;
  850         if (dq->dq_curblocks < dq->dq_bsoftlimit)
  851                 dq->dq_flags &= ~DQ_BLKS;
  852         if (dq->dq_curinodes < dq->dq_isoftlimit)
  853                 dq->dq_flags &= ~DQ_INODS;
  854         if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
  855             dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
  856                 dq->dq_flags |= DQ_FAKE;
  857         else
  858                 dq->dq_flags &= ~DQ_FAKE;
  859         dq->dq_flags |= DQ_MOD;
  860         DQI_UNLOCK(dq);
  861         dqrele(NULLVP, dq);
  862         return (0);
  863 }
  864 
  865 /*
  866  * Q_SETUSE - set current inode and block usage.
  867  */
  868 static int
  869 _setuse(struct thread *td, struct mount *mp, u_long id, int type,
  870     struct dqblk64 *dqb)
  871 {
  872         struct dquot *dq;
  873         struct ufsmount *ump;
  874         struct dquot *ndq;
  875         struct dqblk64 usage;
  876         int error;
  877 
  878         error = priv_check(td, PRIV_UFS_SETUSE);
  879         if (error)
  880                 return (error);
  881 
  882         usage = *dqb;
  883 
  884         ump = VFSTOUFS(mp);
  885         ndq = NODQUOT;
  886 
  887         error = dqget(NULLVP, id, ump, type, &ndq);
  888         if (error)
  889                 return (error);
  890         dq = ndq;
  891         DQI_LOCK(dq);
  892         DQI_WAIT(dq, PINOD+1, "setuse");
  893         /*
  894          * Reset time limit if have a soft limit and were
  895          * previously under it, but are now over it.
  896          */
  897         if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
  898             usage.dqb_curblocks >= dq->dq_bsoftlimit)
  899                 dq->dq_btime = time_second + ump->um_btime[type];
  900         if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
  901             usage.dqb_curinodes >= dq->dq_isoftlimit)
  902                 dq->dq_itime = time_second + ump->um_itime[type];
  903         dq->dq_curblocks = usage.dqb_curblocks;
  904         dq->dq_curinodes = usage.dqb_curinodes;
  905         if (dq->dq_curblocks < dq->dq_bsoftlimit)
  906                 dq->dq_flags &= ~DQ_BLKS;
  907         if (dq->dq_curinodes < dq->dq_isoftlimit)
  908                 dq->dq_flags &= ~DQ_INODS;
  909         dq->dq_flags |= DQ_MOD;
  910         DQI_UNLOCK(dq);
  911         dqrele(NULLVP, dq);
  912         return (0);
  913 }
  914 
  915 int
  916 getquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
  917 {
  918         struct dqblk32 dqb32;
  919         struct dqblk64 dqb64;
  920         int error;
  921 
  922         error = _getquota(td, mp, id, type, &dqb64);
  923         if (error)
  924                 return (error);
  925         dqb64_dqb32(&dqb64, &dqb32);
  926         error = copyout(&dqb32, addr, sizeof(dqb32));
  927         return (error);
  928 }
  929 
  930 int
  931 setquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
  932 {
  933         struct dqblk32 dqb32;
  934         struct dqblk64 dqb64;
  935         int error;
  936 
  937         error = copyin(addr, &dqb32, sizeof(dqb32));
  938         if (error)
  939                 return (error);
  940         dqb32_dqb64(&dqb32, &dqb64);
  941         error = _setquota(td, mp, id, type, &dqb64);
  942         return (error);
  943 }
  944 
  945 int
  946 setuse32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
  947 {
  948         struct dqblk32 dqb32;
  949         struct dqblk64 dqb64;
  950         int error;
  951 
  952         error = copyin(addr, &dqb32, sizeof(dqb32));
  953         if (error)
  954                 return (error);
  955         dqb32_dqb64(&dqb32, &dqb64);
  956         error = _setuse(td, mp, id, type, &dqb64);
  957         return (error);
  958 }
  959 
  960 int
  961 getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
  962 {
  963         struct dqblk64 dqb64;
  964         int error;
  965 
  966         error = _getquota(td, mp, id, type, &dqb64);
  967         if (error)
  968                 return (error);
  969         error = copyout(&dqb64, addr, sizeof(dqb64));
  970         return (error);
  971 }
  972 
  973 int
  974 setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
  975 {
  976         struct dqblk64 dqb64;
  977         int error;
  978 
  979         error = copyin(addr, &dqb64, sizeof(dqb64));
  980         if (error)
  981                 return (error);
  982         error = _setquota(td, mp, id, type, &dqb64);
  983         return (error);
  984 }
  985 
  986 int
  987 setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
  988 {
  989         struct dqblk64 dqb64;
  990         int error;
  991 
  992         error = copyin(addr, &dqb64, sizeof(dqb64));
  993         if (error)
  994                 return (error);
  995         error = _setuse(td, mp, id, type, &dqb64);
  996         return (error);
  997 }
  998 
  999 /*
 1000  * Q_GETQUOTASIZE - get bit-size of quota file fields
 1001  */
 1002 int
 1003 getquotasize(struct thread *td, struct mount *mp, u_long id, int type,
 1004     void *sizep)
 1005 {
 1006         struct ufsmount *ump = VFSTOUFS(mp);
 1007         int bitsize;
 1008 
 1009         UFS_LOCK(ump);
 1010         if (ump->um_quotas[type] == NULLVP ||
 1011             (ump->um_qflags[type] & QTF_CLOSING)) {
 1012                 UFS_UNLOCK(ump);
 1013                 return (EINVAL);
 1014         }
 1015         if ((ump->um_qflags[type] & QTF_64BIT) != 0)
 1016                 bitsize = 64;
 1017         else
 1018                 bitsize = 32;
 1019         UFS_UNLOCK(ump);
 1020         return (copyout(&bitsize, sizep, sizeof(int)));
 1021 }
 1022 
 1023 /*
 1024  * Q_SYNC - sync quota files to disk.
 1025  */
 1026 int
 1027 qsync(struct mount *mp)
 1028 {
 1029         struct ufsmount *ump = VFSTOUFS(mp);
 1030         struct thread *td = curthread;          /* XXX */
 1031         struct vnode *vp, *mvp;
 1032         struct dquot *dq;
 1033         int i, error;
 1034 
 1035         /*
 1036          * Check if the mount point has any quotas.
 1037          * If not, simply return.
 1038          */
 1039         UFS_LOCK(ump);
 1040         for (i = 0; i < MAXQUOTAS; i++)
 1041                 if (ump->um_quotas[i] != NULLVP)
 1042                         break;
 1043         UFS_UNLOCK(ump);
 1044         if (i == MAXQUOTAS)
 1045                 return (0);
 1046         /*
 1047          * Search vnodes associated with this mount point,
 1048          * synchronizing any modified dquot structures.
 1049          */
 1050 again:
 1051         MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
 1052                 if (vp->v_type == VNON) {
 1053                         VI_UNLOCK(vp);
 1054                         continue;
 1055                 }
 1056                 error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td);
 1057                 if (error) {
 1058                         if (error == ENOENT) {
 1059                                 MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp);
 1060                                 goto again;
 1061                         }
 1062                         continue;
 1063                 }
 1064                 for (i = 0; i < MAXQUOTAS; i++) {
 1065                         dq = VTOI(vp)->i_dquot[i];
 1066                         if (dq != NODQUOT)
 1067                                 dqsync(vp, dq);
 1068                 }
 1069                 vput(vp);
 1070         }
 1071         return (0);
 1072 }
 1073 
 1074 /*
 1075  * Sync quota file for given vnode to disk.
 1076  */
 1077 int
 1078 qsyncvp(struct vnode *vp)
 1079 {
 1080         struct ufsmount *ump = VFSTOUFS(vp->v_mount);
 1081         struct dquot *dq;
 1082         int i;
 1083 
 1084         /*
 1085          * Check if the mount point has any quotas.
 1086          * If not, simply return.
 1087          */
 1088         UFS_LOCK(ump);
 1089         for (i = 0; i < MAXQUOTAS; i++)
 1090                 if (ump->um_quotas[i] != NULLVP)
 1091                         break;
 1092         UFS_UNLOCK(ump);
 1093         if (i == MAXQUOTAS)
 1094                 return (0);
 1095         /*
 1096          * Search quotas associated with this vnode
 1097          * synchronizing any modified dquot structures.
 1098          */
 1099         for (i = 0; i < MAXQUOTAS; i++) {
 1100                 dq = VTOI(vp)->i_dquot[i];
 1101                 if (dq != NODQUOT)
 1102                         dqsync(vp, dq);
 1103         }
 1104         return (0);
 1105 }
 1106 
 1107 /*
 1108  * Code pertaining to management of the in-core dquot data structures.
 1109  */
 1110 #define DQHASH(dqvp, id) \
 1111         (&dqhashtbl[((((intptr_t)(dqvp)) >> 8) + id) & dqhash])
 1112 static LIST_HEAD(dqhash, dquot) *dqhashtbl;
 1113 static u_long dqhash;
 1114 
 1115 /*
 1116  * Dquot free list.
 1117  */
 1118 #define DQUOTINC        5       /* minimum free dquots desired */
 1119 static TAILQ_HEAD(dqfreelist, dquot) dqfreelist;
 1120 static long numdquot, desireddquot = DQUOTINC;
 1121 
 1122 /*
 1123  * Lock to protect quota hash, dq free list and dq_cnt ref counters of
 1124  * _all_ dqs.
 1125  */
 1126 struct mtx dqhlock;
 1127 
 1128 #define DQH_LOCK()      mtx_lock(&dqhlock)
 1129 #define DQH_UNLOCK()    mtx_unlock(&dqhlock)
 1130 
 1131 static struct dquot *dqhashfind(struct dqhash *dqh, u_long id,
 1132         struct vnode *dqvp);
 1133 
 1134 /*
 1135  * Initialize the quota system.
 1136  */
 1137 void
 1138 dqinit(void)
 1139 {
 1140 
 1141         mtx_init(&dqhlock, "dqhlock", NULL, MTX_DEF);
 1142         dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash);
 1143         TAILQ_INIT(&dqfreelist);
 1144 }
 1145 
 1146 /*
 1147  * Shut down the quota system.
 1148  */
 1149 void
 1150 dquninit(void)
 1151 {
 1152         struct dquot *dq;
 1153 
 1154         hashdestroy(dqhashtbl, M_DQUOT, dqhash);
 1155         while ((dq = TAILQ_FIRST(&dqfreelist)) != NULL) {
 1156                 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
 1157                 mtx_destroy(&dq->dq_lock);
 1158                 free(dq, M_DQUOT);
 1159         }
 1160         mtx_destroy(&dqhlock);
 1161 }
 1162 
 1163 static struct dquot *
 1164 dqhashfind(struct dqhash *dqh, u_long id, struct vnode *dqvp)
 1165 {
 1166         struct dquot *dq;
 1167 
 1168         mtx_assert(&dqhlock, MA_OWNED);
 1169         LIST_FOREACH(dq, dqh, dq_hash) {
 1170                 if (dq->dq_id != id ||
 1171                     dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
 1172                         continue;
 1173                 /*
 1174                  * Cache hit with no references.  Take
 1175                  * the structure off the free list.
 1176                  */
 1177                 if (dq->dq_cnt == 0)
 1178                         TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
 1179                 DQREF(dq);
 1180                 return (dq);
 1181         }
 1182         return (NODQUOT);
 1183 }
 1184 
 1185 /*
 1186  * Determine the quota file type.
 1187  *
 1188  * A 32-bit quota file is simply an array of struct dqblk32.
 1189  *
 1190  * A 64-bit quota file is a struct dqhdr64 followed by an array of struct
 1191  * dqblk64.  The header contains various magic bits which allow us to be
 1192  * reasonably confident that it is indeeda 64-bit quota file and not just
 1193  * a 32-bit quota file that just happens to "look right".
 1194  *
 1195  */
 1196 static int
 1197 dqopen(struct vnode *vp, struct ufsmount *ump, int type)
 1198 {
 1199         struct dqhdr64 dqh;
 1200         struct iovec aiov;
 1201         struct uio auio;
 1202         int error;
 1203 
 1204         ASSERT_VOP_LOCKED(vp, "dqopen");
 1205         auio.uio_iov = &aiov;
 1206         auio.uio_iovcnt = 1;
 1207         aiov.iov_base = &dqh;
 1208         aiov.iov_len = sizeof(dqh);
 1209         auio.uio_resid = sizeof(dqh);
 1210         auio.uio_offset = 0;
 1211         auio.uio_segflg = UIO_SYSSPACE;
 1212         auio.uio_rw = UIO_READ;
 1213         auio.uio_td = (struct thread *)0;
 1214         error = VOP_READ(vp, &auio, 0, ump->um_cred[type]);
 1215 
 1216         if (error != 0)
 1217                 return (error);
 1218         if (auio.uio_resid > 0) {
 1219                 /* assume 32 bits */
 1220                 return (0);
 1221         }
 1222 
 1223         UFS_LOCK(ump);
 1224         if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 &&
 1225             be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION &&
 1226             be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) &&
 1227             be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64)) {
 1228                 /* XXX: what if the magic matches, but the sizes are wrong? */
 1229                 ump->um_qflags[type] |= QTF_64BIT;
 1230         } else {
 1231                 ump->um_qflags[type] &= ~QTF_64BIT;
 1232         }
 1233         UFS_UNLOCK(ump);
 1234 
 1235         return (0);
 1236 }
 1237 
 1238 /*
 1239  * Obtain a dquot structure for the specified identifier and quota file
 1240  * reading the information from the file if necessary.
 1241  */
 1242 static int
 1243 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
 1244     struct dquot **dqp)
 1245 {
 1246         uint8_t buf[sizeof(struct dqblk64)];
 1247         off_t base, recsize;
 1248         struct dquot *dq, *dq1;
 1249         struct dqhash *dqh;
 1250         struct vnode *dqvp;
 1251         struct iovec aiov;
 1252         struct uio auio;
 1253         int vfslocked, dqvplocked, error;
 1254 
 1255 #ifdef DEBUG_VFS_LOCKS
 1256         if (vp != NULLVP)
 1257                 ASSERT_VOP_ELOCKED(vp, "dqget");
 1258 #endif
 1259 
 1260         if (vp != NULLVP && *dqp != NODQUOT) {
 1261                 return (0);
 1262         }
 1263 
 1264         /* XXX: Disallow negative id values to prevent the
 1265         * creation of 100GB+ quota data files.
 1266         */
 1267         if ((int)id < 0)
 1268                 return (EINVAL);
 1269 
 1270         UFS_LOCK(ump);
 1271         dqvp = ump->um_quotas[type];
 1272         if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
 1273                 *dqp = NODQUOT;
 1274                 UFS_UNLOCK(ump);
 1275                 return (EINVAL);
 1276         }
 1277         vref(dqvp);
 1278         UFS_UNLOCK(ump);
 1279         error = 0;
 1280         dqvplocked = 0;
 1281 
 1282         /*
 1283          * Check the cache first.
 1284          */
 1285         dqh = DQHASH(dqvp, id);
 1286         DQH_LOCK();
 1287         dq = dqhashfind(dqh, id, dqvp);
 1288         if (dq != NULL) {
 1289                 DQH_UNLOCK();
 1290 hfound:         DQI_LOCK(dq);
 1291                 DQI_WAIT(dq, PINOD+1, "dqget");
 1292                 DQI_UNLOCK(dq);
 1293                 if (dq->dq_ump == NULL) {
 1294                         dqrele(vp, dq);
 1295                         dq = NODQUOT;
 1296                         error = EIO;
 1297                 }
 1298                 *dqp = dq;
 1299                 vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 1300                 if (dqvplocked)
 1301                         vput(dqvp);
 1302                 else
 1303                         vrele(dqvp);
 1304                 VFS_UNLOCK_GIANT(vfslocked);
 1305                 return (error);
 1306         }
 1307 
 1308         /*
 1309          * Quota vnode lock is before DQ_LOCK. Acquire dqvp lock there
 1310          * since new dq will appear on the hash chain DQ_LOCKed.
 1311          */
 1312         if (vp != dqvp) {
 1313                 DQH_UNLOCK();
 1314                 vn_lock(dqvp, LK_SHARED | LK_RETRY);
 1315                 dqvplocked = 1;
 1316                 DQH_LOCK();
 1317                 /*
 1318                  * Recheck the cache after sleep for quota vnode lock.
 1319                  */
 1320                 dq = dqhashfind(dqh, id, dqvp);
 1321                 if (dq != NULL) {
 1322                         DQH_UNLOCK();
 1323                         goto hfound;
 1324                 }
 1325         }
 1326 
 1327         /*
 1328          * Not in cache, allocate a new one or take it from the
 1329          * free list.
 1330          */
 1331         if (TAILQ_FIRST(&dqfreelist) == NODQUOT &&
 1332             numdquot < MAXQUOTAS * desiredvnodes)
 1333                 desireddquot += DQUOTINC;
 1334         if (numdquot < desireddquot) {
 1335                 numdquot++;
 1336                 DQH_UNLOCK();
 1337                 dq1 = malloc(sizeof *dq1, M_DQUOT, M_WAITOK | M_ZERO);
 1338                 mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF);
 1339                 DQH_LOCK();
 1340                 /*
 1341                  * Recheck the cache after sleep for memory.
 1342                  */
 1343                 dq = dqhashfind(dqh, id, dqvp);
 1344                 if (dq != NULL) {
 1345                         numdquot--;
 1346                         DQH_UNLOCK();
 1347                         mtx_destroy(&dq1->dq_lock);
 1348                         free(dq1, M_DQUOT);
 1349                         goto hfound;
 1350                 }
 1351                 dq = dq1;
 1352         } else {
 1353                 if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) {
 1354                         DQH_UNLOCK();
 1355                         tablefull("dquot");
 1356                         *dqp = NODQUOT;
 1357                         vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 1358                         if (dqvplocked)
 1359                                 vput(dqvp);
 1360                         else
 1361                                 vrele(dqvp);
 1362                         VFS_UNLOCK_GIANT(vfslocked);
 1363                         return (EUSERS);
 1364                 }
 1365                 if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
 1366                         panic("dqget: free dquot isn't %p", dq);
 1367                 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
 1368                 if (dq->dq_ump != NULL)
 1369                         LIST_REMOVE(dq, dq_hash);
 1370         }
 1371 
 1372         /*
 1373          * Dq is put into hash already locked to prevent parallel
 1374          * usage while it is being read from file.
 1375          */
 1376         dq->dq_flags = DQ_LOCK;
 1377         dq->dq_id = id;
 1378         dq->dq_type = type;
 1379         dq->dq_ump = ump;
 1380         LIST_INSERT_HEAD(dqh, dq, dq_hash);
 1381         DQREF(dq);
 1382         DQH_UNLOCK();
 1383 
 1384         /*
 1385          * Read the requested quota record from the quota file, performing
 1386          * any necessary conversions.
 1387          */
 1388         if (ump->um_qflags[type] & QTF_64BIT) {
 1389                 recsize = sizeof(struct dqblk64);
 1390                 base = sizeof(struct dqhdr64);
 1391         } else {
 1392                 recsize = sizeof(struct dqblk32);
 1393                 base = 0;
 1394         }
 1395         auio.uio_iov = &aiov;
 1396         auio.uio_iovcnt = 1;
 1397         aiov.iov_base = buf;
 1398         aiov.iov_len = recsize;
 1399         auio.uio_resid = recsize;
 1400         auio.uio_offset = base + id * recsize;
 1401         auio.uio_segflg = UIO_SYSSPACE;
 1402         auio.uio_rw = UIO_READ;
 1403         auio.uio_td = (struct thread *)0;
 1404 
 1405         vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 1406         error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
 1407         if (auio.uio_resid == recsize && error == 0) {
 1408                 bzero(&dq->dq_dqb, sizeof(dq->dq_dqb));
 1409         } else {
 1410                 if (ump->um_qflags[type] & QTF_64BIT)
 1411                         dqb64_dq((struct dqblk64 *)buf, dq);
 1412                 else
 1413                         dqb32_dq((struct dqblk32 *)buf, dq);
 1414         }
 1415         if (dqvplocked)
 1416                 vput(dqvp);
 1417         else
 1418                 vrele(dqvp);
 1419         VFS_UNLOCK_GIANT(vfslocked);
 1420         /*
 1421          * I/O error in reading quota file, release
 1422          * quota structure and reflect problem to caller.
 1423          */
 1424         if (error) {
 1425                 DQH_LOCK();
 1426                 dq->dq_ump = NULL;
 1427                 LIST_REMOVE(dq, dq_hash);
 1428                 DQH_UNLOCK();
 1429                 DQI_LOCK(dq);
 1430                 if (dq->dq_flags & DQ_WANT)
 1431                         wakeup(dq);
 1432                 dq->dq_flags = 0;
 1433                 DQI_UNLOCK(dq);
 1434                 dqrele(vp, dq);
 1435                 *dqp = NODQUOT;
 1436                 return (error);
 1437         }
 1438         DQI_LOCK(dq);
 1439         /*
 1440          * Check for no limit to enforce.
 1441          * Initialize time values if necessary.
 1442          */
 1443         if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
 1444             dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
 1445                 dq->dq_flags |= DQ_FAKE;
 1446         if (dq->dq_id != 0) {
 1447                 if (dq->dq_btime == 0) {
 1448                         dq->dq_btime = time_second + ump->um_btime[type];
 1449                         if (dq->dq_bsoftlimit &&
 1450                             dq->dq_curblocks >= dq->dq_bsoftlimit)
 1451                                 dq->dq_flags |= DQ_MOD;
 1452                 }
 1453                 if (dq->dq_itime == 0) {
 1454                         dq->dq_itime = time_second + ump->um_itime[type];
 1455                         if (dq->dq_isoftlimit &&
 1456                             dq->dq_curinodes >= dq->dq_isoftlimit)
 1457                                 dq->dq_flags |= DQ_MOD;
 1458                 }
 1459         }
 1460         DQI_WAKEUP(dq);
 1461         DQI_UNLOCK(dq);
 1462         *dqp = dq;
 1463         return (0);
 1464 }
 1465 
 1466 #ifdef DIAGNOSTIC
 1467 /*
 1468  * Obtain a reference to a dquot.
 1469  */
 1470 static void
 1471 dqref(struct dquot *dq)
 1472 {
 1473 
 1474         dq->dq_cnt++;
 1475 }
 1476 #endif
 1477 
 1478 /*
 1479  * Release a reference to a dquot.
 1480  */
 1481 void
 1482 dqrele(struct vnode *vp, struct dquot *dq)
 1483 {
 1484 
 1485         if (dq == NODQUOT)
 1486                 return;
 1487         DQH_LOCK();
 1488         KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 1", dq));
 1489         if (dq->dq_cnt > 1) {
 1490                 dq->dq_cnt--;
 1491                 DQH_UNLOCK();
 1492                 return;
 1493         }
 1494         DQH_UNLOCK();
 1495 sync:
 1496         (void) dqsync(vp, dq);
 1497 
 1498         DQH_LOCK();
 1499         KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 2", dq));
 1500         if (--dq->dq_cnt > 0)
 1501         {
 1502                 DQH_UNLOCK();
 1503                 return;
 1504         }
 1505 
 1506         /*
 1507          * The dq may become dirty after it is synced but before it is
 1508          * put to the free list. Checking the DQ_MOD there without
 1509          * locking dq should be safe since no other references to the
 1510          * dq exist.
 1511          */
 1512         if ((dq->dq_flags & DQ_MOD) != 0) {
 1513                 dq->dq_cnt++;
 1514                 DQH_UNLOCK();
 1515                 goto sync;
 1516         }
 1517         TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
 1518         DQH_UNLOCK();
 1519 }
 1520 
 1521 /*
 1522  * Update the disk quota in the quota file.
 1523  */
 1524 static int
 1525 dqsync(struct vnode *vp, struct dquot *dq)
 1526 {
 1527         uint8_t buf[sizeof(struct dqblk64)];
 1528         off_t base, recsize;
 1529         struct vnode *dqvp;
 1530         struct iovec aiov;
 1531         struct uio auio;
 1532         int vfslocked, error;
 1533         struct mount *mp;
 1534         struct ufsmount *ump;
 1535 
 1536 #ifdef DEBUG_VFS_LOCKS
 1537         if (vp != NULL)
 1538                 ASSERT_VOP_ELOCKED(vp, "dqsync");
 1539 #endif
 1540 
 1541         mp = NULL;
 1542         error = 0;
 1543         if (dq == NODQUOT)
 1544                 panic("dqsync: dquot");
 1545         if ((ump = dq->dq_ump) == NULL)
 1546                 return (0);
 1547         UFS_LOCK(ump);
 1548         if ((dqvp = ump->um_quotas[dq->dq_type]) == NULLVP)
 1549                 panic("dqsync: file");
 1550         vref(dqvp);
 1551         UFS_UNLOCK(ump);
 1552 
 1553         vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 1554         DQI_LOCK(dq);
 1555         if ((dq->dq_flags & DQ_MOD) == 0) {
 1556                 DQI_UNLOCK(dq);
 1557                 vrele(dqvp);
 1558                 VFS_UNLOCK_GIANT(vfslocked);
 1559                 return (0);
 1560         }
 1561         DQI_UNLOCK(dq);
 1562 
 1563         (void) vn_start_secondary_write(dqvp, &mp, V_WAIT);
 1564         if (vp != dqvp)
 1565                 vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
 1566 
 1567         VFS_UNLOCK_GIANT(vfslocked);
 1568         DQI_LOCK(dq);
 1569         DQI_WAIT(dq, PINOD+2, "dqsync");
 1570         if ((dq->dq_flags & DQ_MOD) == 0)
 1571                 goto out;
 1572         dq->dq_flags |= DQ_LOCK;
 1573         DQI_UNLOCK(dq);
 1574 
 1575         /*
 1576          * Write the quota record to the quota file, performing any
 1577          * necessary conversions.  See dqget() for additional details.
 1578          */
 1579         if (ump->um_qflags[dq->dq_type] & QTF_64BIT) {
 1580                 dq_dqb64(dq, (struct dqblk64 *)buf);
 1581                 recsize = sizeof(struct dqblk64);
 1582                 base = sizeof(struct dqhdr64);
 1583         } else {
 1584                 dq_dqb32(dq, (struct dqblk32 *)buf);
 1585                 recsize = sizeof(struct dqblk32);
 1586                 base = 0;
 1587         }
 1588 
 1589         auio.uio_iov = &aiov;
 1590         auio.uio_iovcnt = 1;
 1591         aiov.iov_base = buf;
 1592         aiov.iov_len = recsize;
 1593         auio.uio_resid = recsize;
 1594         auio.uio_offset = base + dq->dq_id * recsize;
 1595         auio.uio_segflg = UIO_SYSSPACE;
 1596         auio.uio_rw = UIO_WRITE;
 1597         auio.uio_td = (struct thread *)0;
 1598         vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 1599         error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
 1600         VFS_UNLOCK_GIANT(vfslocked);
 1601         if (auio.uio_resid && error == 0)
 1602                 error = EIO;
 1603 
 1604         DQI_LOCK(dq);
 1605         DQI_WAKEUP(dq);
 1606         dq->dq_flags &= ~DQ_MOD;
 1607 out:
 1608         DQI_UNLOCK(dq);
 1609         vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 1610         if (vp != dqvp)
 1611                 vput(dqvp);
 1612         else
 1613                 vrele(dqvp);
 1614         vn_finished_secondary_write(mp);
 1615         VFS_UNLOCK_GIANT(vfslocked);
 1616         return (error);
 1617 }
 1618 
 1619 /*
 1620  * Flush all entries from the cache for a particular vnode.
 1621  */
 1622 static int
 1623 dqflush(struct vnode *vp)
 1624 {
 1625         struct dquot *dq, *nextdq;
 1626         struct dqhash *dqh;
 1627         int error;
 1628 
 1629         /*
 1630          * Move all dquot's that used to refer to this quota
 1631          * file off their hash chains (they will eventually
 1632          * fall off the head of the free list and be re-used).
 1633          */
 1634         error = 0;
 1635         DQH_LOCK();
 1636         for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) {
 1637                 for (dq = LIST_FIRST(dqh); dq; dq = nextdq) {
 1638                         nextdq = LIST_NEXT(dq, dq_hash);
 1639                         if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
 1640                                 continue;
 1641                         if (dq->dq_cnt)
 1642                                 error = EBUSY;
 1643                         else {
 1644                                 LIST_REMOVE(dq, dq_hash);
 1645                                 dq->dq_ump = NULL;
 1646                         }
 1647                 }
 1648         }
 1649         DQH_UNLOCK();
 1650         return (error);
 1651 }
 1652 
 1653 /*
 1654  * The following three functions are provided for the adjustment of
 1655  * quotas by the soft updates code.
 1656  */
 1657 #ifdef SOFTUPDATES
 1658 /*
 1659  * Acquire a reference to the quota structures associated with a vnode.
 1660  * Return count of number of quota structures found.
 1661  */
 1662 int
 1663 quotaref(vp, qrp)
 1664         struct vnode *vp;
 1665         struct dquot **qrp;
 1666 {
 1667         struct inode *ip;
 1668         struct dquot *dq;
 1669         int i, found;
 1670 
 1671         for (i = 0; i < MAXQUOTAS; i++)
 1672                 qrp[i] = NODQUOT;
 1673         /*
 1674          * Disk quotas must be turned off for system files.  Currently
 1675          * snapshot and quota files.
 1676          */
 1677         if ((vp->v_vflag & VV_SYSTEM) != 0)
 1678                 return (0);
 1679         /*
 1680          * Iterate through and copy active quotas.
 1681          */
 1682         found = 0;
 1683         ip = VTOI(vp);
 1684         mtx_lock(&dqhlock);
 1685         for (i = 0; i < MAXQUOTAS; i++) {
 1686                 if ((dq = ip->i_dquot[i]) == NODQUOT)
 1687                         continue;
 1688                 DQREF(dq);
 1689                 qrp[i] = dq;
 1690                 found++;
 1691         }
 1692         mtx_unlock(&dqhlock);
 1693         return (found);
 1694 }
 1695 
 1696 /*
 1697  * Release a set of quota structures obtained from a vnode.
 1698  */
 1699 void
 1700 quotarele(qrp)
 1701         struct dquot **qrp;
 1702 {
 1703         struct dquot *dq;
 1704         int i;
 1705 
 1706         for (i = 0; i < MAXQUOTAS; i++) {
 1707                 if ((dq = qrp[i]) == NODQUOT)
 1708                         continue;
 1709                 dqrele(NULL, dq);
 1710         }
 1711 }
 1712 
 1713 /*
 1714  * Adjust the number of blocks associated with a quota.
 1715  * Positive numbers when adding blocks; negative numbers when freeing blocks.
 1716  */
 1717 void
 1718 quotaadj(qrp, ump, blkcount)
 1719         struct dquot **qrp;
 1720         struct ufsmount *ump;
 1721         int64_t blkcount;
 1722 {
 1723         struct dquot *dq;
 1724         ufs2_daddr_t ncurblocks;
 1725         int i;
 1726 
 1727         if (blkcount == 0)
 1728                 return;
 1729         for (i = 0; i < MAXQUOTAS; i++) {
 1730                 if ((dq = qrp[i]) == NODQUOT)
 1731                         continue;
 1732                 DQI_LOCK(dq);
 1733                 DQI_WAIT(dq, PINOD+1, "adjqta");
 1734                 ncurblocks = dq->dq_curblocks + blkcount;
 1735                 if (ncurblocks >= 0)
 1736                         dq->dq_curblocks = ncurblocks;
 1737                 else
 1738                         dq->dq_curblocks = 0;
 1739                 if (blkcount < 0)
 1740                         dq->dq_flags &= ~DQ_BLKS;
 1741                 else if (dq->dq_curblocks + blkcount >= dq->dq_bsoftlimit &&
 1742                          dq->dq_curblocks < dq->dq_bsoftlimit)
 1743                         dq->dq_btime = time_second + ump->um_btime[i];
 1744                 dq->dq_flags |= DQ_MOD;
 1745                 DQI_UNLOCK(dq);
 1746         }
 1747 }
 1748 #endif /* SOFTUPDATES */
 1749 
 1750 /*
 1751  * 32-bit / 64-bit conversion functions.
 1752  *
 1753  * 32-bit quota records are stored in native byte order.  Attention must
 1754  * be paid to overflow issues.
 1755  *
 1756  * 64-bit quota records are stored in network byte order.
 1757  */
 1758 
 1759 #define CLIP32(u64) (u64 > UINT32_MAX ? UINT32_MAX : (uint32_t)u64)
 1760 
 1761 /*
 1762  * Convert 32-bit host-order structure to dquot.
 1763  */
 1764 static void
 1765 dqb32_dq(const struct dqblk32 *dqb32, struct dquot *dq)
 1766 {
 1767 
 1768         dq->dq_bhardlimit = dqb32->dqb_bhardlimit;
 1769         dq->dq_bsoftlimit = dqb32->dqb_bsoftlimit;
 1770         dq->dq_curblocks = dqb32->dqb_curblocks;
 1771         dq->dq_ihardlimit = dqb32->dqb_ihardlimit;
 1772         dq->dq_isoftlimit = dqb32->dqb_isoftlimit;
 1773         dq->dq_curinodes = dqb32->dqb_curinodes;
 1774         dq->dq_btime = dqb32->dqb_btime;
 1775         dq->dq_itime = dqb32->dqb_itime;
 1776 }
 1777 
 1778 /*
 1779  * Convert 64-bit network-order structure to dquot.
 1780  */
 1781 static void
 1782 dqb64_dq(const struct dqblk64 *dqb64, struct dquot *dq)
 1783 {
 1784 
 1785         dq->dq_bhardlimit = be64toh(dqb64->dqb_bhardlimit);
 1786         dq->dq_bsoftlimit = be64toh(dqb64->dqb_bsoftlimit);
 1787         dq->dq_curblocks = be64toh(dqb64->dqb_curblocks);
 1788         dq->dq_ihardlimit = be64toh(dqb64->dqb_ihardlimit);
 1789         dq->dq_isoftlimit = be64toh(dqb64->dqb_isoftlimit);
 1790         dq->dq_curinodes = be64toh(dqb64->dqb_curinodes);
 1791         dq->dq_btime = be64toh(dqb64->dqb_btime);
 1792         dq->dq_itime = be64toh(dqb64->dqb_itime);
 1793 }
 1794 
 1795 /*
 1796  * Convert dquot to 32-bit host-order structure.
 1797  */
 1798 static void
 1799 dq_dqb32(const struct dquot *dq, struct dqblk32 *dqb32)
 1800 {
 1801 
 1802         dqb32->dqb_bhardlimit = CLIP32(dq->dq_bhardlimit);
 1803         dqb32->dqb_bsoftlimit = CLIP32(dq->dq_bsoftlimit);
 1804         dqb32->dqb_curblocks = CLIP32(dq->dq_curblocks);
 1805         dqb32->dqb_ihardlimit = CLIP32(dq->dq_ihardlimit);
 1806         dqb32->dqb_isoftlimit = CLIP32(dq->dq_isoftlimit);
 1807         dqb32->dqb_curinodes = CLIP32(dq->dq_curinodes);
 1808         dqb32->dqb_btime = CLIP32(dq->dq_btime);
 1809         dqb32->dqb_itime = CLIP32(dq->dq_itime);
 1810 }
 1811 
 1812 /*
 1813  * Convert dquot to 64-bit network-order structure.
 1814  */
 1815 static void
 1816 dq_dqb64(const struct dquot *dq, struct dqblk64 *dqb64)
 1817 {
 1818 
 1819         dqb64->dqb_bhardlimit = htobe64(dq->dq_bhardlimit);
 1820         dqb64->dqb_bsoftlimit = htobe64(dq->dq_bsoftlimit);
 1821         dqb64->dqb_curblocks = htobe64(dq->dq_curblocks);
 1822         dqb64->dqb_ihardlimit = htobe64(dq->dq_ihardlimit);
 1823         dqb64->dqb_isoftlimit = htobe64(dq->dq_isoftlimit);
 1824         dqb64->dqb_curinodes = htobe64(dq->dq_curinodes);
 1825         dqb64->dqb_btime = htobe64(dq->dq_btime);
 1826         dqb64->dqb_itime = htobe64(dq->dq_itime);
 1827 }
 1828 
 1829 /*
 1830  * Convert 64-bit host-order structure to 32-bit host-order structure.
 1831  */
 1832 static void
 1833 dqb64_dqb32(const struct dqblk64 *dqb64, struct dqblk32 *dqb32)
 1834 {
 1835 
 1836         dqb32->dqb_bhardlimit = CLIP32(dqb64->dqb_bhardlimit);
 1837         dqb32->dqb_bsoftlimit = CLIP32(dqb64->dqb_bsoftlimit);
 1838         dqb32->dqb_curblocks = CLIP32(dqb64->dqb_curblocks);
 1839         dqb32->dqb_ihardlimit = CLIP32(dqb64->dqb_ihardlimit);
 1840         dqb32->dqb_isoftlimit = CLIP32(dqb64->dqb_isoftlimit);
 1841         dqb32->dqb_curinodes = CLIP32(dqb64->dqb_curinodes);
 1842         dqb32->dqb_btime = CLIP32(dqb64->dqb_btime);
 1843         dqb32->dqb_itime = CLIP32(dqb64->dqb_itime);
 1844 }
 1845 
 1846 /*
 1847  * Convert 32-bit host-order structure to 64-bit host-order structure.
 1848  */
 1849 static void
 1850 dqb32_dqb64(const struct dqblk32 *dqb32, struct dqblk64 *dqb64)
 1851 {
 1852 
 1853         dqb64->dqb_bhardlimit = dqb32->dqb_bhardlimit;
 1854         dqb64->dqb_bsoftlimit = dqb32->dqb_bsoftlimit;
 1855         dqb64->dqb_curblocks = dqb32->dqb_curblocks;
 1856         dqb64->dqb_ihardlimit = dqb32->dqb_ihardlimit;
 1857         dqb64->dqb_isoftlimit = dqb32->dqb_isoftlimit;
 1858         dqb64->dqb_curinodes = dqb32->dqb_curinodes;
 1859         dqb64->dqb_btime = dqb32->dqb_btime;
 1860         dqb64->dqb_itime = dqb32->dqb_itime;
 1861 }

Cache object: 68bfce25b88f01d127fae395fea88a23


[ 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.