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

unix.superglobalmegacorp.com

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