Annotation of Net2/ufs/ufs_quota.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
        !             3:  * 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:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by the University of
        !            19:  *     California, Berkeley and its contributors.
        !            20:  * 4. Neither the name of the University nor the names of its contributors
        !            21:  *    may be used to endorse or promote products derived from this software
        !            22:  *    without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  *     @(#)ufs_quota.c 7.11 (Berkeley) 6/21/91
        !            37:  */
        !            38: #include "param.h"
        !            39: #include "kernel.h"
        !            40: #include "systm.h"
        !            41: #include "namei.h"
        !            42: #include "malloc.h"
        !            43: #include "file.h"
        !            44: #include "proc.h"
        !            45: #include "vnode.h"
        !            46: #include "mount.h"
        !            47: 
        !            48: #include "fs.h"
        !            49: #include "quota.h"
        !            50: #include "inode.h"
        !            51: #include "ufsmount.h"
        !            52: 
        !            53: /*
        !            54:  * Quota name to error message mapping.
        !            55:  */
        !            56: static char *quotatypes[] = INITQFNAMES;
        !            57: 
        !            58: /*
        !            59:  * Set up the quotas for an inode.
        !            60:  *
        !            61:  * This routine completely defines the semantics of quotas.
        !            62:  * If other criterion want to be used to establish quotas, the
        !            63:  * MAXQUOTAS value in quotas.h should be increased, and the
        !            64:  * additional dquots set up here.
        !            65:  */
        !            66: getinoquota(ip)
        !            67:        register struct inode *ip;
        !            68: {
        !            69:        struct ufsmount *ump;
        !            70:        struct vnode *vp = ITOV(ip);
        !            71:        int error;
        !            72: 
        !            73:        ump = VFSTOUFS(vp->v_mount);
        !            74:        /*
        !            75:         * Set up the user quota based on file uid.
        !            76:         * EINVAL means that quotas are not enabled.
        !            77:         */
        !            78:        if (ip->i_dquot[USRQUOTA] == NODQUOT &&
        !            79:            (error =
        !            80:                dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
        !            81:            error != EINVAL)
        !            82:                return (error);
        !            83:        /*
        !            84:         * Set up the group quota based on file gid.
        !            85:         * EINVAL means that quotas are not enabled.
        !            86:         */
        !            87:        if (ip->i_dquot[GRPQUOTA] == NODQUOT &&
        !            88:            (error =
        !            89:                dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
        !            90:            error != EINVAL)
        !            91:                return (error);
        !            92:        return (0);
        !            93: }
        !            94: 
        !            95: /*
        !            96:  * Update disk usage, and take corrective action.
        !            97:  */
        !            98: chkdq(ip, change, cred, flags)
        !            99:        register struct inode *ip;
        !           100:        long change;
        !           101:        struct ucred *cred;
        !           102:        int flags;
        !           103: {
        !           104:        register struct dquot *dq;
        !           105:        register int i;
        !           106:        int ncurblocks, error;
        !           107: 
        !           108: #ifdef DIAGNOSTIC
        !           109:        if ((flags & CHOWN) == 0)
        !           110:                chkdquot(ip);
        !           111: #endif
        !           112:        if (change == 0)
        !           113:                return (0);
        !           114:        if (change < 0) {
        !           115:                for (i = 0; i < MAXQUOTAS; i++) {
        !           116:                        if ((dq = ip->i_dquot[i]) == NODQUOT)
        !           117:                                continue;
        !           118:                        while (dq->dq_flags & DQ_LOCK) {
        !           119:                                dq->dq_flags |= DQ_WANT;
        !           120:                                sleep((caddr_t)dq, PINOD+1);
        !           121:                        }
        !           122:                        ncurblocks = dq->dq_curblocks + change;
        !           123:                        if (ncurblocks >= 0)
        !           124:                                dq->dq_curblocks = ncurblocks;
        !           125:                        else
        !           126:                                dq->dq_curblocks = 0;
        !           127:                        dq->dq_flags &= ~DQ_BLKS;
        !           128:                        dq->dq_flags |= DQ_MOD;
        !           129:                }
        !           130:                return (0);
        !           131:        }
        !           132:        if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
        !           133:                for (i = 0; i < MAXQUOTAS; i++) {
        !           134:                        if ((dq = ip->i_dquot[i]) == NODQUOT)
        !           135:                                continue;
        !           136:                        if (error = chkdqchg(ip, change, cred, i))
        !           137:                                return (error);
        !           138:                }
        !           139:        }
        !           140:        for (i = 0; i < MAXQUOTAS; i++) {
        !           141:                if ((dq = ip->i_dquot[i]) == NODQUOT)
        !           142:                        continue;
        !           143:                while (dq->dq_flags & DQ_LOCK) {
        !           144:                        dq->dq_flags |= DQ_WANT;
        !           145:                        sleep((caddr_t)dq, PINOD+1);
        !           146:                }
        !           147:                dq->dq_curblocks += change;
        !           148:                dq->dq_flags |= DQ_MOD;
        !           149:        }
        !           150:        return (0);
        !           151: }
        !           152: 
        !           153: /*
        !           154:  * Check for a valid change to a users allocation.
        !           155:  * Issue an error message if appropriate.
        !           156:  */
        !           157: chkdqchg(ip, change, cred, type)
        !           158:        struct inode *ip;
        !           159:        long change;
        !           160:        struct ucred *cred;
        !           161:        int type;
        !           162: {
        !           163:        register struct dquot *dq = ip->i_dquot[type];
        !           164:        long ncurblocks = dq->dq_curblocks + change;
        !           165: 
        !           166:        /*
        !           167:         * If user would exceed their hard limit, disallow space allocation.
        !           168:         */
        !           169:        if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
        !           170:                if ((dq->dq_flags & DQ_BLKS) == 0 &&
        !           171:                    ip->i_uid == cred->cr_uid) {
        !           172:                        uprintf("\n%s: write failed, %s disk limit reached\n",
        !           173:                            ip->i_fs->fs_fsmnt, quotatypes[type]);
        !           174:                        dq->dq_flags |= DQ_BLKS;
        !           175:                }
        !           176:                return (EDQUOT);
        !           177:        }
        !           178:        /*
        !           179:         * If user is over their soft limit for too long, disallow space
        !           180:         * allocation. Reset time limit as they cross their soft limit.
        !           181:         */
        !           182:        if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
        !           183:                if (dq->dq_curblocks < dq->dq_bsoftlimit) {
        !           184:                        dq->dq_btime = time.tv_sec +
        !           185:                            VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type];
        !           186:                        if (ip->i_uid == cred->cr_uid)
        !           187:                                uprintf("\n%s: warning, %s %s\n",
        !           188:                                    ip->i_fs->fs_fsmnt, quotatypes[type],
        !           189:                                    "disk quota exceeded");
        !           190:                        return (0);
        !           191:                }
        !           192:                if (time.tv_sec > dq->dq_btime) {
        !           193:                        if ((dq->dq_flags & DQ_BLKS) == 0 &&
        !           194:                            ip->i_uid == cred->cr_uid) {
        !           195:                                uprintf("\n%s: write failed, %s %s\n",
        !           196:                                    ip->i_fs->fs_fsmnt, quotatypes[type],
        !           197:                                    "disk quota exceeded too long");
        !           198:                                dq->dq_flags |= DQ_BLKS;
        !           199:                        }
        !           200:                        return (EDQUOT);
        !           201:                }
        !           202:        }
        !           203:        return (0);
        !           204: }
        !           205: 
        !           206: /*
        !           207:  * Check the inode limit, applying corrective action.
        !           208:  */
        !           209: chkiq(ip, change, cred, flags)
        !           210:        register struct inode *ip;
        !           211:        long change;
        !           212:        struct ucred *cred;
        !           213:        int flags;
        !           214: {
        !           215:        register struct dquot *dq;
        !           216:        register int i;
        !           217:        int ncurinodes, error;
        !           218: 
        !           219: #ifdef DIAGNOSTIC
        !           220:        if ((flags & CHOWN) == 0)
        !           221:                chkdquot(ip);
        !           222: #endif
        !           223:        if (change == 0)
        !           224:                return (0);
        !           225:        if (change < 0) {
        !           226:                for (i = 0; i < MAXQUOTAS; i++) {
        !           227:                        if ((dq = ip->i_dquot[i]) == NODQUOT)
        !           228:                                continue;
        !           229:                        while (dq->dq_flags & DQ_LOCK) {
        !           230:                                dq->dq_flags |= DQ_WANT;
        !           231:                                sleep((caddr_t)dq, PINOD+1);
        !           232:                        }
        !           233:                        ncurinodes = dq->dq_curinodes + change;
        !           234:                        if (ncurinodes >= 0)
        !           235:                                dq->dq_curinodes = ncurinodes;
        !           236:                        else
        !           237:                                dq->dq_curinodes = 0;
        !           238:                        dq->dq_flags &= ~DQ_INODS;
        !           239:                        dq->dq_flags |= DQ_MOD;
        !           240:                }
        !           241:                return (0);
        !           242:        }
        !           243:        if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
        !           244:                for (i = 0; i < MAXQUOTAS; i++) {
        !           245:                        if ((dq = ip->i_dquot[i]) == NODQUOT)
        !           246:                                continue;
        !           247:                        if (error = chkiqchg(ip, change, cred, i))
        !           248:                                return (error);
        !           249:                }
        !           250:        }
        !           251:        for (i = 0; i < MAXQUOTAS; i++) {
        !           252:                if ((dq = ip->i_dquot[i]) == NODQUOT)
        !           253:                        continue;
        !           254:                while (dq->dq_flags & DQ_LOCK) {
        !           255:                        dq->dq_flags |= DQ_WANT;
        !           256:                        sleep((caddr_t)dq, PINOD+1);
        !           257:                }
        !           258:                dq->dq_curinodes += change;
        !           259:                dq->dq_flags |= DQ_MOD;
        !           260:        }
        !           261:        return (0);
        !           262: }
        !           263: 
        !           264: /*
        !           265:  * Check for a valid change to a users allocation.
        !           266:  * Issue an error message if appropriate.
        !           267:  */
        !           268: chkiqchg(ip, change, cred, type)
        !           269:        struct inode *ip;
        !           270:        long change;
        !           271:        struct ucred *cred;
        !           272:        int type;
        !           273: {
        !           274:        register struct dquot *dq = ip->i_dquot[type];
        !           275:        long ncurinodes = dq->dq_curinodes + change;
        !           276: 
        !           277:        /*
        !           278:         * If user would exceed their hard limit, disallow inode allocation.
        !           279:         */
        !           280:        if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
        !           281:                if ((dq->dq_flags & DQ_INODS) == 0 &&
        !           282:                    ip->i_uid == cred->cr_uid) {
        !           283:                        uprintf("\n%s: write failed, %s inode limit reached\n",
        !           284:                            ip->i_fs->fs_fsmnt, quotatypes[type]);
        !           285:                        dq->dq_flags |= DQ_INODS;
        !           286:                }
        !           287:                return (EDQUOT);
        !           288:        }
        !           289:        /*
        !           290:         * If user is over their soft limit for too long, disallow inode
        !           291:         * allocation. Reset time limit as they cross their soft limit.
        !           292:         */
        !           293:        if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
        !           294:                if (dq->dq_curinodes < dq->dq_isoftlimit) {
        !           295:                        dq->dq_itime = time.tv_sec +
        !           296:                            VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type];
        !           297:                        if (ip->i_uid == cred->cr_uid)
        !           298:                                uprintf("\n%s: warning, %s %s\n",
        !           299:                                    ip->i_fs->fs_fsmnt, quotatypes[type],
        !           300:                                    "inode quota exceeded");
        !           301:                        return (0);
        !           302:                }
        !           303:                if (time.tv_sec > dq->dq_itime) {
        !           304:                        if ((dq->dq_flags & DQ_INODS) == 0 &&
        !           305:                            ip->i_uid == cred->cr_uid) {
        !           306:                                uprintf("\n%s: write failed, %s %s\n",
        !           307:                                    ip->i_fs->fs_fsmnt, quotatypes[type],
        !           308:                                    "inode quota exceeded too long");
        !           309:                                dq->dq_flags |= DQ_INODS;
        !           310:                        }
        !           311:                        return (EDQUOT);
        !           312:                }
        !           313:        }
        !           314:        return (0);
        !           315: }
        !           316: 
        !           317: #ifdef DIAGNOSTIC
        !           318: /*
        !           319:  * On filesystems with quotas enabled,
        !           320:  * it is an error for a file to change size and not
        !           321:  * to have a dquot structure associated with it.
        !           322:  */
        !           323: chkdquot(ip)
        !           324:        register struct inode *ip;
        !           325: {
        !           326:        struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount);
        !           327:        register int i;
        !           328: 
        !           329:        for (i = 0; i < MAXQUOTAS; i++) {
        !           330:                if (ump->um_quotas[i] == NULLVP ||
        !           331:                    (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
        !           332:                        continue;
        !           333:                if (ip->i_dquot[i] == NODQUOT) {
        !           334:                        vprint("chkdquot: missing dquot", ITOV(ip));
        !           335:                        panic("missing dquot");
        !           336:                }
        !           337:        }
        !           338: }
        !           339: #endif /* DIAGNOSTIC */
        !           340: 
        !           341: /*
        !           342:  * Code to process quotactl commands.
        !           343:  */
        !           344: 
        !           345: /*
        !           346:  * Q_QUOTAON - set up a quota file for a particular file system.
        !           347:  */
        !           348: quotaon(p, mp, type, fname)
        !           349:        struct proc *p;
        !           350:        struct mount *mp;
        !           351:        register int type;
        !           352:        caddr_t fname;
        !           353: {
        !           354:        register struct ufsmount *ump = VFSTOUFS(mp);
        !           355:        register struct vnode *vp, **vpp;
        !           356:        struct vnode *nextvp;
        !           357:        struct dquot *dq;
        !           358:        int error;
        !           359:        struct nameidata nd;
        !           360: 
        !           361:        vpp = &ump->um_quotas[type];
        !           362:        nd.ni_segflg = UIO_USERSPACE;
        !           363:        nd.ni_dirp = fname;
        !           364:        if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
        !           365:                return (error);
        !           366:        vp = nd.ni_vp;
        !           367:        VOP_UNLOCK(vp);
        !           368:        if (vp->v_type != VREG) {
        !           369:                (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
        !           370:                return (EACCES);
        !           371:        }
        !           372:        if (vfs_busy(mp)) {
        !           373:                (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
        !           374:                return (EBUSY);
        !           375:        }
        !           376:        if (*vpp != vp)
        !           377:                quotaoff(p, mp, type);
        !           378:        ump->um_qflags[type] |= QTF_OPENING;
        !           379:        mp->mnt_flag |= MNT_QUOTA;
        !           380:        vp->v_flag |= VSYSTEM;
        !           381:        *vpp = vp;
        !           382:        /*
        !           383:         * Save the credential of the process that turned on quotas.
        !           384:         * Set up the time limits for this quota.
        !           385:         */
        !           386:        crhold(p->p_ucred);
        !           387:        ump->um_cred[type] = p->p_ucred;
        !           388:        ump->um_btime[type] = MAX_DQ_TIME;
        !           389:        ump->um_itime[type] = MAX_IQ_TIME;
        !           390:        if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
        !           391:                if (dq->dq_btime > 0)
        !           392:                        ump->um_btime[type] = dq->dq_btime;
        !           393:                if (dq->dq_itime > 0)
        !           394:                        ump->um_itime[type] = dq->dq_itime;
        !           395:                dqrele(NULLVP, dq);
        !           396:        }
        !           397:        /*
        !           398:         * Search vnodes associated with this mount point,
        !           399:         * adding references to quota file being opened.
        !           400:         * NB: only need to add dquot's for inodes being modified.
        !           401:         */
        !           402: again:
        !           403:        for (vp = mp->mnt_mounth; vp; vp = nextvp) {
        !           404:                nextvp = vp->v_mountf;
        !           405:                if (vp->v_writecount == 0)
        !           406:                        continue;
        !           407:                if (vget(vp))
        !           408:                        goto again;
        !           409:                if (error = getinoquota(VTOI(vp))) {
        !           410:                        vput(vp);
        !           411:                        break;
        !           412:                }
        !           413:                vput(vp);
        !           414:                if (vp->v_mountf != nextvp || vp->v_mount != mp)
        !           415:                        goto again;
        !           416:        }
        !           417:        ump->um_qflags[type] &= ~QTF_OPENING;
        !           418:        if (error)
        !           419:                quotaoff(p, mp, type);
        !           420:        vfs_unbusy(mp);
        !           421:        return (error);
        !           422: }
        !           423: 
        !           424: /*
        !           425:  * Q_QUOTAOFF - turn off disk quotas for a filesystem.
        !           426:  */
        !           427: quotaoff(p, mp, type)
        !           428:        struct proc *p;
        !           429:        struct mount *mp;
        !           430:        register int type;
        !           431: {
        !           432:        register struct vnode *vp;
        !           433:        struct vnode *qvp, *nextvp;
        !           434:        struct ufsmount *ump = VFSTOUFS(mp);
        !           435:        register struct dquot *dq;
        !           436:        register struct inode *ip;
        !           437:        int error;
        !           438:        
        !           439:        if ((mp->mnt_flag & MNT_MPBUSY) == 0)
        !           440:                panic("quotaoff: not busy");
        !           441:        if ((qvp = ump->um_quotas[type]) == NULLVP)
        !           442:                return (0);
        !           443:        ump->um_qflags[type] |= QTF_CLOSING;
        !           444:        /*
        !           445:         * Search vnodes associated with this mount point,
        !           446:         * deleting any references to quota file being closed.
        !           447:         */
        !           448: again:
        !           449:        for (vp = mp->mnt_mounth; vp; vp = nextvp) {
        !           450:                nextvp = vp->v_mountf;
        !           451:                if (vget(vp))
        !           452:                        goto again;
        !           453:                ip = VTOI(vp);
        !           454:                dq = ip->i_dquot[type];
        !           455:                ip->i_dquot[type] = NODQUOT;
        !           456:                dqrele(vp, dq);
        !           457:                vput(vp);
        !           458:                if (vp->v_mountf != nextvp || vp->v_mount != mp)
        !           459:                        goto again;
        !           460:        }
        !           461:        dqflush(qvp);
        !           462:        qvp->v_flag &= ~VSYSTEM;
        !           463:        error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);
        !           464:        ump->um_quotas[type] = NULLVP;
        !           465:        crfree(ump->um_cred[type]);
        !           466:        ump->um_cred[type] = NOCRED;
        !           467:        ump->um_qflags[type] &= ~QTF_CLOSING;
        !           468:        for (type = 0; type < MAXQUOTAS; type++)
        !           469:                if (ump->um_quotas[type] != NULLVP)
        !           470:                        break;
        !           471:        if (type == MAXQUOTAS)
        !           472:                mp->mnt_flag &= ~MNT_QUOTA;
        !           473:        return (error);
        !           474: }
        !           475: 
        !           476: /*
        !           477:  * Q_GETQUOTA - return current values in a dqblk structure.
        !           478:  */
        !           479: getquota(mp, id, type, addr)
        !           480:        struct mount *mp;
        !           481:        u_long id;
        !           482:        int type;
        !           483:        caddr_t addr;
        !           484: {
        !           485:        struct dquot *dq;
        !           486:        int error;
        !           487: 
        !           488:        if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq))
        !           489:                return (error);
        !           490:        error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));
        !           491:        dqrele(NULLVP, dq);
        !           492:        return (error);
        !           493: }
        !           494: 
        !           495: /*
        !           496:  * Q_SETQUOTA - assign an entire dqblk structure.
        !           497:  */
        !           498: setquota(mp, id, type, addr)
        !           499:        struct mount *mp;
        !           500:        u_long id;
        !           501:        int type;
        !           502:        caddr_t addr;
        !           503: {
        !           504:        register struct dquot *dq;
        !           505:        struct dquot *ndq;
        !           506:        struct ufsmount *ump = VFSTOUFS(mp);
        !           507:        struct dqblk newlim;
        !           508:        int error;
        !           509: 
        !           510:        if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))
        !           511:                return (error);
        !           512:        if (error = dqget(NULLVP, id, ump, type, &ndq))
        !           513:                return (error);
        !           514:        dq = ndq;
        !           515:        while (dq->dq_flags & DQ_LOCK) {
        !           516:                dq->dq_flags |= DQ_WANT;
        !           517:                sleep((caddr_t)dq, PINOD+1);
        !           518:        }
        !           519:        /*
        !           520:         * Copy all but the current values.
        !           521:         * Reset time limit if previously had no soft limit or were
        !           522:         * under it, but now have a soft limit and are over it.
        !           523:         */
        !           524:        newlim.dqb_curblocks = dq->dq_curblocks;
        !           525:        newlim.dqb_curinodes = dq->dq_curinodes;
        !           526:        if (dq->dq_id != 0) {
        !           527:                newlim.dqb_btime = dq->dq_btime;
        !           528:                newlim.dqb_itime = dq->dq_itime;
        !           529:        }
        !           530:        if (newlim.dqb_bsoftlimit &&
        !           531:            dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
        !           532:            (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
        !           533:                newlim.dqb_btime = time.tv_sec + ump->um_btime[type];
        !           534:        if (newlim.dqb_isoftlimit &&
        !           535:            dq->dq_curinodes >= newlim.dqb_isoftlimit &&
        !           536:            (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
        !           537:                newlim.dqb_itime = time.tv_sec + ump->um_itime[type];
        !           538:        dq->dq_dqb = newlim;
        !           539:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
        !           540:                dq->dq_flags &= ~DQ_BLKS;
        !           541:        if (dq->dq_curinodes < dq->dq_isoftlimit)
        !           542:                dq->dq_flags &= ~DQ_INODS;
        !           543:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
        !           544:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
        !           545:                dq->dq_flags |= DQ_FAKE;
        !           546:        else
        !           547:                dq->dq_flags &= ~DQ_FAKE;
        !           548:        dq->dq_flags |= DQ_MOD;
        !           549:        dqrele(NULLVP, dq);
        !           550:        return (0);
        !           551: }
        !           552: 
        !           553: /*
        !           554:  * Q_SETUSE - set current inode and block usage.
        !           555:  */
        !           556: setuse(mp, id, type, addr)
        !           557:        struct mount *mp;
        !           558:        u_long id;
        !           559:        int type;
        !           560:        caddr_t addr;
        !           561: {
        !           562:        register struct dquot *dq;
        !           563:        struct ufsmount *ump = VFSTOUFS(mp);
        !           564:        struct dquot *ndq;
        !           565:        struct dqblk usage;
        !           566:        int error;
        !           567: 
        !           568:        if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))
        !           569:                return (error);
        !           570:        if (error = dqget(NULLVP, id, ump, type, &ndq))
        !           571:                return (error);
        !           572:        dq = ndq;
        !           573:        while (dq->dq_flags & DQ_LOCK) {
        !           574:                dq->dq_flags |= DQ_WANT;
        !           575:                sleep((caddr_t)dq, PINOD+1);
        !           576:        }
        !           577:        /*
        !           578:         * Reset time limit if have a soft limit and were
        !           579:         * previously under it, but are now over it.
        !           580:         */
        !           581:        if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
        !           582:            usage.dqb_curblocks >= dq->dq_bsoftlimit)
        !           583:                dq->dq_btime = time.tv_sec + ump->um_btime[type];
        !           584:        if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
        !           585:            usage.dqb_curinodes >= dq->dq_isoftlimit)
        !           586:                dq->dq_itime = time.tv_sec + ump->um_itime[type];
        !           587:        dq->dq_curblocks = usage.dqb_curblocks;
        !           588:        dq->dq_curinodes = usage.dqb_curinodes;
        !           589:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
        !           590:                dq->dq_flags &= ~DQ_BLKS;
        !           591:        if (dq->dq_curinodes < dq->dq_isoftlimit)
        !           592:                dq->dq_flags &= ~DQ_INODS;
        !           593:        dq->dq_flags |= DQ_MOD;
        !           594:        dqrele(NULLVP, dq);
        !           595:        return (0);
        !           596: }
        !           597: 
        !           598: /*
        !           599:  * Q_SYNC - sync quota files to disk.
        !           600:  */
        !           601: qsync(mp)
        !           602:        struct mount *mp;
        !           603: {
        !           604:        struct ufsmount *ump = VFSTOUFS(mp);
        !           605:        register struct vnode *vp, *nextvp;
        !           606:        register struct dquot *dq;
        !           607:        register int i;
        !           608: 
        !           609:        /*
        !           610:         * Check if the mount point has any quotas.
        !           611:         * If not, simply return.
        !           612:         */
        !           613:        if ((mp->mnt_flag & MNT_MPBUSY) == 0)
        !           614:                panic("qsync: not busy");
        !           615:        for (i = 0; i < MAXQUOTAS; i++)
        !           616:                if (ump->um_quotas[i] != NULLVP)
        !           617:                        break;
        !           618:        if (i == MAXQUOTAS)
        !           619:                return (0);
        !           620:        /*
        !           621:         * Search vnodes associated with this mount point,
        !           622:         * synchronizing any modified dquot structures.
        !           623:         */
        !           624: again:
        !           625:        for (vp = mp->mnt_mounth; vp; vp = nextvp) {
        !           626:                nextvp = vp->v_mountf;
        !           627:                if (VOP_ISLOCKED(vp))
        !           628:                        continue;
        !           629:                if (vget(vp))
        !           630:                        goto again;
        !           631:                for (i = 0; i < MAXQUOTAS; i++) {
        !           632:                        dq = VTOI(vp)->i_dquot[i];
        !           633:                        if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
        !           634:                                dqsync(vp, dq);
        !           635:                }
        !           636:                vput(vp);
        !           637:                if (vp->v_mountf != nextvp || vp->v_mount != mp)
        !           638:                        goto again;
        !           639:        }
        !           640:        return (0);
        !           641: }
        !           642: 
        !           643: /*
        !           644:  * Code pertaining to management of the in-core dquot data structures.
        !           645:  */
        !           646: 
        !           647: /*
        !           648:  * Dquot cache - hash chain headers.
        !           649:  */
        !           650: union  dqhead  {
        !           651:        union   dqhead  *dqh_head[2];
        !           652:        struct  dquot   *dqh_chain[2];
        !           653: };
        !           654: #define        dqh_forw        dqh_chain[0]
        !           655: #define        dqh_back        dqh_chain[1]
        !           656: 
        !           657: union dqhead *dqhashtbl;
        !           658: long dqhash;
        !           659: 
        !           660: /*
        !           661:  * Dquot free list.
        !           662:  */
        !           663: #define        DQUOTINC        5       /* minimum free dquots desired */
        !           664: struct dquot *dqfreel, **dqback = &dqfreel;
        !           665: long numdquot, desireddquot = DQUOTINC;
        !           666: 
        !           667: /*
        !           668:  * Initialize the quota system.
        !           669:  */
        !           670: dqinit()
        !           671: {
        !           672:        register union dqhead *dhp;
        !           673:        register long dqhashsize;
        !           674: 
        !           675:        dqhashsize = roundup((desiredvnodes + 1) * sizeof *dhp / 2,
        !           676:                NBPG * CLSIZE);
        !           677:        dqhashtbl = (union dqhead *)malloc(dqhashsize, M_DQUOT, M_WAITOK);
        !           678:        for (dqhash = 1; dqhash <= dqhashsize / sizeof *dhp; dqhash <<= 1)
        !           679:                /* void */;
        !           680:        dqhash = (dqhash >> 1) - 1;
        !           681:        for (dhp = &dqhashtbl[dqhash]; dhp >= dqhashtbl; dhp--) {
        !           682:                dhp->dqh_head[0] = dhp;
        !           683:                dhp->dqh_head[1] = dhp;
        !           684:        }
        !           685: }
        !           686: 
        !           687: /*
        !           688:  * Obtain a dquot structure for the specified identifier and quota file
        !           689:  * reading the information from the file if necessary.
        !           690:  */
        !           691: dqget(vp, id, ump, type, dqp)
        !           692:        struct vnode *vp;
        !           693:        u_long id;
        !           694:        register struct ufsmount *ump;
        !           695:        register int type;
        !           696:        struct dquot **dqp;
        !           697: {
        !           698:        register struct dquot *dq;
        !           699:        register union dqhead *dh;
        !           700:        register struct dquot *dp;
        !           701:        register struct vnode *dqvp;
        !           702:        struct iovec aiov;
        !           703:        struct uio auio;
        !           704:        int error;
        !           705: 
        !           706:        dqvp = ump->um_quotas[type];
        !           707:        if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
        !           708:                *dqp = NODQUOT;
        !           709:                return (EINVAL);
        !           710:        }
        !           711:        /*
        !           712:         * Check the cache first.
        !           713:         */
        !           714:        dh = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash];
        !           715:        for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = dq->dq_forw) {
        !           716:                if (dq->dq_id != id ||
        !           717:                    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
        !           718:                        continue;
        !           719:                /*
        !           720:                 * Cache hit with no references.  Take
        !           721:                 * the structure off the free list.
        !           722:                 */
        !           723:                if (dq->dq_cnt == 0) {
        !           724:                        dp = dq->dq_freef;
        !           725:                        if (dp != NODQUOT)
        !           726:                                dp->dq_freeb = dq->dq_freeb;
        !           727:                        else
        !           728:                                dqback = dq->dq_freeb;
        !           729:                        *dq->dq_freeb = dp;
        !           730:                }
        !           731:                DQREF(dq);
        !           732:                *dqp = dq;
        !           733:                return (0);
        !           734:        }
        !           735:        /*
        !           736:         * Not in cache, allocate a new one.
        !           737:         */
        !           738:        if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes)
        !           739:                desireddquot += DQUOTINC;
        !           740:        if (numdquot < desireddquot) {
        !           741:                dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK);
        !           742:                bzero((char *)dq, sizeof *dq);
        !           743:                numdquot++;
        !           744:        } else {
        !           745:                if ((dq = dqfreel) == NULL) {
        !           746:                        tablefull("dquot");
        !           747:                        *dqp = NODQUOT;
        !           748:                        return (EUSERS);
        !           749:                }
        !           750:                if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
        !           751:                        panic("free dquot isn't");
        !           752:                if ((dp = dq->dq_freef) != NODQUOT)
        !           753:                        dp->dq_freeb = &dqfreel;
        !           754:                else
        !           755:                        dqback = &dqfreel;
        !           756:                dqfreel = dp;
        !           757:                dq->dq_freef = NULL;
        !           758:                dq->dq_freeb = NULL;
        !           759:                remque(dq);
        !           760:        }
        !           761:        /*
        !           762:         * Initialize the contents of the dquot structure.
        !           763:         */
        !           764:        if (vp != dqvp)
        !           765:                VOP_LOCK(dqvp);
        !           766:        insque(dq, dh);
        !           767:        DQREF(dq);
        !           768:        dq->dq_flags = DQ_LOCK;
        !           769:        dq->dq_id = id;
        !           770:        dq->dq_ump = ump;
        !           771:        dq->dq_type = type;
        !           772:        auio.uio_iov = &aiov;
        !           773:        auio.uio_iovcnt = 1;
        !           774:        aiov.iov_base = (caddr_t)&dq->dq_dqb;
        !           775:        aiov.iov_len = sizeof (struct dqblk);
        !           776:        auio.uio_resid = sizeof (struct dqblk);
        !           777:        auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
        !           778:        auio.uio_segflg = UIO_SYSSPACE;
        !           779:        auio.uio_rw = UIO_READ;
        !           780:        auio.uio_procp = (struct proc *)0;
        !           781:        error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
        !           782:        if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
        !           783:                bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk));
        !           784:        if (vp != dqvp)
        !           785:                VOP_UNLOCK(dqvp);
        !           786:        if (dq->dq_flags & DQ_WANT)
        !           787:                wakeup((caddr_t)dq);
        !           788:        dq->dq_flags = 0;
        !           789:        /*
        !           790:         * I/O error in reading quota file, release
        !           791:         * quota structure and reflect problem to caller.
        !           792:         */
        !           793:        if (error) {
        !           794:                remque(dq);
        !           795:                dq->dq_forw = dq;       /* on a private, unfindable hash list */
        !           796:                dq->dq_back = dq;
        !           797:                dqrele(vp, dq);
        !           798:                *dqp = NODQUOT;
        !           799:                return (error);
        !           800:        }
        !           801:        /*
        !           802:         * Check for no limit to enforce.
        !           803:         * Initialize time values if necessary.
        !           804:         */
        !           805:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
        !           806:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
        !           807:                dq->dq_flags |= DQ_FAKE;
        !           808:        if (dq->dq_id != 0) {
        !           809:                if (dq->dq_btime == 0)
        !           810:                        dq->dq_btime = time.tv_sec + ump->um_btime[type];
        !           811:                if (dq->dq_itime == 0)
        !           812:                        dq->dq_itime = time.tv_sec + ump->um_itime[type];
        !           813:        }
        !           814:        *dqp = dq;
        !           815:        return (0);
        !           816: }
        !           817: 
        !           818: /*
        !           819:  * Obtain a reference to a dquot.
        !           820:  */
        !           821: dqref(dq)
        !           822:        struct dquot *dq;
        !           823: {
        !           824: 
        !           825:        dq->dq_cnt++;
        !           826: }
        !           827: 
        !           828: /*
        !           829:  * Release a reference to a dquot.
        !           830:  */
        !           831: dqrele(vp, dq)
        !           832:        struct vnode *vp;
        !           833:        register struct dquot *dq;
        !           834: {
        !           835: 
        !           836:        if (dq == NODQUOT)
        !           837:                return;
        !           838:        if (dq->dq_cnt > 1) {
        !           839:                dq->dq_cnt--;
        !           840:                return;
        !           841:        }
        !           842:        if (dq->dq_flags & DQ_MOD)
        !           843:                (void) dqsync(vp, dq);
        !           844:        if (--dq->dq_cnt > 0)
        !           845:                return;
        !           846:        if (dqfreel != NODQUOT) {
        !           847:                *dqback = dq;
        !           848:                dq->dq_freeb = dqback;
        !           849:        } else {
        !           850:                dqfreel = dq;
        !           851:                dq->dq_freeb = &dqfreel;
        !           852:        }
        !           853:        dq->dq_freef = NODQUOT;
        !           854:        dqback = &dq->dq_freef;
        !           855: }
        !           856: 
        !           857: /*
        !           858:  * Update the disk quota in the quota file.
        !           859:  */
        !           860: dqsync(vp, dq)
        !           861:        struct vnode *vp;
        !           862:        register struct dquot *dq;
        !           863: {
        !           864:        struct vnode *dqvp;
        !           865:        struct iovec aiov;
        !           866:        struct uio auio;
        !           867:        int error;
        !           868: 
        !           869:        if (dq == NODQUOT)
        !           870:                panic("dqsync: dquot");
        !           871:        if ((dq->dq_flags & DQ_MOD) == 0)
        !           872:                return (0);
        !           873:        if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
        !           874:                panic("dqsync: file");
        !           875:        if (vp != dqvp)
        !           876:                VOP_LOCK(dqvp);
        !           877:        while (dq->dq_flags & DQ_LOCK) {
        !           878:                dq->dq_flags |= DQ_WANT;
        !           879:                sleep((caddr_t)dq, PINOD+2);
        !           880:                if ((dq->dq_flags & DQ_MOD) == 0) {
        !           881:                        if (vp != dqvp)
        !           882:                                VOP_UNLOCK(dqvp);
        !           883:                        return (0);
        !           884:                }
        !           885:        }
        !           886:        dq->dq_flags |= DQ_LOCK;
        !           887:        auio.uio_iov = &aiov;
        !           888:        auio.uio_iovcnt = 1;
        !           889:        aiov.iov_base = (caddr_t)&dq->dq_dqb;
        !           890:        aiov.iov_len = sizeof (struct dqblk);
        !           891:        auio.uio_resid = sizeof (struct dqblk);
        !           892:        auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
        !           893:        auio.uio_segflg = UIO_SYSSPACE;
        !           894:        auio.uio_rw = UIO_WRITE;
        !           895:        auio.uio_procp = (struct proc *)0;
        !           896:        error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
        !           897:        if (auio.uio_resid && error == 0)
        !           898:                error = EIO;
        !           899:        if (dq->dq_flags & DQ_WANT)
        !           900:                wakeup((caddr_t)dq);
        !           901:        dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);
        !           902:        if (vp != dqvp)
        !           903:                VOP_UNLOCK(dqvp);
        !           904:        return (error);
        !           905: }
        !           906: 
        !           907: /*
        !           908:  * Flush all entries from the cache for a particular vnode.
        !           909:  */
        !           910: dqflush(vp)
        !           911:        register struct vnode *vp;
        !           912: {
        !           913:        register union dqhead *dh;
        !           914:        register struct dquot *dq, *nextdq;
        !           915: 
        !           916:        /*
        !           917:         * Move all dquot's that used to refer to this quota
        !           918:         * file off their hash chains (they will eventually
        !           919:         * fall off the head of the free list and be re-used).
        !           920:         */
        !           921:        for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) {
        !           922:                for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) {
        !           923:                        nextdq = dq->dq_forw;
        !           924:                        if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
        !           925:                                continue;
        !           926:                        if (dq->dq_cnt)
        !           927:                                panic("dqflush: stray dquot");
        !           928:                        remque(dq);
        !           929:                        dq->dq_forw = dq;
        !           930:                        dq->dq_back = dq;
        !           931:                        dq->dq_ump = (struct ufsmount *)0;
        !           932:                }
        !           933:        }
        !           934: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.