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

Cache object: e4804b524d005742aa4f6f0293a3883a


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