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

Cache object: a5354ef99771fcbdafc6d2db07ff865c


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