[BACK]Return to ufs_quota1.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ufs / ufs

Annotation of src/sys/ufs/ufs/ufs_quota1.c, Revision 1.9

1.9     ! dholland    1: /*     $NetBSD: ufs_quota1.c,v 1.8 2012/01/29 06:38:24 dholland Exp $  */
1.2       bouyer      2:
                      3: /*
                      4:  * Copyright (c) 1982, 1986, 1990, 1993, 1995
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Robert Elz at The University of Melbourne.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. Neither the name of the University nor the names of its contributors
                     19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
                     34:  *     @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
                     35:  */
                     36:
                     37: #include <sys/cdefs.h>
1.9     ! dholland   38: __KERNEL_RCSID(0, "$NetBSD: ufs_quota1.c,v 1.8 2012/01/29 06:38:24 dholland Exp $");
1.2       bouyer     39:
                     40: #include <sys/param.h>
                     41: #include <sys/kernel.h>
                     42: #include <sys/systm.h>
                     43: #include <sys/namei.h>
                     44: #include <sys/file.h>
                     45: #include <sys/proc.h>
                     46: #include <sys/vnode.h>
                     47: #include <sys/mount.h>
                     48: #include <sys/kauth.h>
                     49:
1.3       bouyer     50: #include <quota/quotaprop.h>
1.2       bouyer     51: #include <ufs/ufs/quota1.h>
                     52: #include <ufs/ufs/inode.h>
                     53: #include <ufs/ufs/ufsmount.h>
                     54: #include <ufs/ufs/ufs_extern.h>
                     55: #include <ufs/ufs/ufs_quota.h>
                     56:
                     57: static int chkdqchg(struct inode *, int64_t, kauth_cred_t, int);
                     58: static int chkiqchg(struct inode *, int32_t, kauth_cred_t, int);
                     59:
                     60: /*
                     61:  * Update disk usage, and take corrective action.
                     62:  */
                     63: int
                     64: chkdq1(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
                     65: {
                     66:        struct dquot *dq;
                     67:        int i;
                     68:        int ncurblocks, error;
                     69:
                     70:        if ((error = getinoquota(ip)) != 0)
                     71:                return error;
                     72:        if (change == 0)
                     73:                return (0);
                     74:        if (change < 0) {
                     75:                for (i = 0; i < MAXQUOTAS; i++) {
                     76:                        if ((dq = ip->i_dquot[i]) == NODQUOT)
                     77:                                continue;
                     78:                        mutex_enter(&dq->dq_interlock);
                     79:                        ncurblocks = dq->dq_curblocks + change;
                     80:                        if (ncurblocks >= 0)
                     81:                                dq->dq_curblocks = ncurblocks;
                     82:                        else
                     83:                                dq->dq_curblocks = 0;
                     84:                        dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                     85:                        dq->dq_flags |= DQ_MOD;
                     86:                        mutex_exit(&dq->dq_interlock);
                     87:                }
                     88:                return (0);
                     89:        }
                     90:        for (i = 0; i < MAXQUOTAS; i++) {
                     91:                if ((dq = ip->i_dquot[i]) == NODQUOT)
                     92:                        continue;
                     93:                if ((flags & FORCE) == 0 &&
                     94:                    kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA,
                     95:                    KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, KAUTH_ARG(i),
                     96:                    KAUTH_ARG(QL_BLOCK), NULL) != 0) {
                     97:                        mutex_enter(&dq->dq_interlock);
                     98:                        error = chkdqchg(ip, change, cred, i);
                     99:                        mutex_exit(&dq->dq_interlock);
                    100:                        if (error != 0)
                    101:                                return (error);
                    102:                }
                    103:        }
                    104:        for (i = 0; i < MAXQUOTAS; i++) {
                    105:                if ((dq = ip->i_dquot[i]) == NODQUOT)
                    106:                        continue;
                    107:                mutex_enter(&dq->dq_interlock);
                    108:                dq->dq_curblocks += change;
                    109:                dq->dq_flags |= DQ_MOD;
                    110:                mutex_exit(&dq->dq_interlock);
                    111:        }
                    112:        return (0);
                    113: }
                    114:
                    115: /*
                    116:  * Check for a valid change to a users allocation.
                    117:  * Issue an error message if appropriate.
                    118:  */
                    119: static int
                    120: chkdqchg(struct inode *ip, int64_t change, kauth_cred_t cred, int type)
                    121: {
                    122:        struct dquot *dq = ip->i_dquot[type];
                    123:        long ncurblocks = dq->dq_curblocks + change;
                    124:
                    125:        KASSERT(mutex_owned(&dq->dq_interlock));
                    126:        /*
                    127:         * If user would exceed their hard limit, disallow space allocation.
                    128:         */
                    129:        if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
                    130:                if ((dq->dq_flags & DQ_WARN(QL_BLOCK)) == 0 &&
                    131:                    ip->i_uid == kauth_cred_geteuid(cred)) {
                    132:                        uprintf("\n%s: write failed, %s disk limit reached\n",
                    133:                            ITOV(ip)->v_mount->mnt_stat.f_mntonname,
                    134:                            quotatypes[type]);
                    135:                        dq->dq_flags |= DQ_WARN(QL_BLOCK);
                    136:                }
                    137:                return (EDQUOT);
                    138:        }
                    139:        /*
                    140:         * If user is over their soft limit for too long, disallow space
                    141:         * allocation. Reset time limit as they cross their soft limit.
                    142:         */
                    143:        if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
                    144:                if (dq->dq_curblocks < dq->dq_bsoftlimit) {
                    145:                        dq->dq_btime =
                    146:                            time_second + ip->i_ump->umq1_btime[type];
                    147:                        if (ip->i_uid == kauth_cred_geteuid(cred))
                    148:                                uprintf("\n%s: warning, %s %s\n",
                    149:                                    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
                    150:                                    quotatypes[type], "disk quota exceeded");
                    151:                        return (0);
                    152:                }
                    153:                if (time_second > dq->dq_btime) {
                    154:                        if ((dq->dq_flags & DQ_WARN(QL_BLOCK)) == 0 &&
                    155:                            ip->i_uid == kauth_cred_geteuid(cred)) {
                    156:                                uprintf("\n%s: write failed, %s %s\n",
                    157:                                    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
                    158:                                    quotatypes[type],
                    159:                                    "disk quota exceeded for too long");
                    160:                                dq->dq_flags |= DQ_WARN(QL_BLOCK);
                    161:                        }
                    162:                        return (EDQUOT);
                    163:                }
                    164:        }
                    165:        return (0);
                    166: }
                    167:
                    168: /*
                    169:  * Check the inode limit, applying corrective action.
                    170:  */
                    171: int
                    172: chkiq1(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
                    173: {
                    174:        struct dquot *dq;
                    175:        int i;
                    176:        int ncurinodes, error;
                    177:
                    178:        if ((error = getinoquota(ip)) != 0)
                    179:                return error;
                    180:        if (change == 0)
                    181:                return (0);
                    182:        if (change < 0) {
                    183:                for (i = 0; i < MAXQUOTAS; i++) {
                    184:                        if ((dq = ip->i_dquot[i]) == NODQUOT)
                    185:                                continue;
                    186:                        mutex_enter(&dq->dq_interlock);
                    187:                        ncurinodes = dq->dq_curinodes + change;
                    188:                        if (ncurinodes >= 0)
                    189:                                dq->dq_curinodes = ncurinodes;
                    190:                        else
                    191:                                dq->dq_curinodes = 0;
                    192:                        dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    193:                        dq->dq_flags |= DQ_MOD;
                    194:                        mutex_exit(&dq->dq_interlock);
                    195:                }
                    196:                return (0);
                    197:        }
                    198:        for (i = 0; i < MAXQUOTAS; i++) {
                    199:                if ((dq = ip->i_dquot[i]) == NODQUOT)
                    200:                        continue;
                    201:                if ((flags & FORCE) == 0 && kauth_authorize_system(cred,
                    202:                    KAUTH_SYSTEM_FS_QUOTA, KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT,
                    203:                    KAUTH_ARG(i), KAUTH_ARG(QL_FILE), NULL) != 0) {
                    204:                        mutex_enter(&dq->dq_interlock);
                    205:                        error = chkiqchg(ip, change, cred, i);
                    206:                        mutex_exit(&dq->dq_interlock);
                    207:                        if (error != 0)
                    208:                                return (error);
                    209:                }
                    210:        }
                    211:        for (i = 0; i < MAXQUOTAS; i++) {
                    212:                if ((dq = ip->i_dquot[i]) == NODQUOT)
                    213:                        continue;
                    214:                mutex_enter(&dq->dq_interlock);
                    215:                dq->dq_curinodes += change;
                    216:                dq->dq_flags |= DQ_MOD;
                    217:                mutex_exit(&dq->dq_interlock);
                    218:        }
                    219:        return (0);
                    220: }
                    221:
                    222: /*
                    223:  * Check for a valid change to a users allocation.
                    224:  * Issue an error message if appropriate.
                    225:  */
                    226: static int
                    227: chkiqchg(struct inode *ip, int32_t change, kauth_cred_t cred, int type)
                    228: {
                    229:        struct dquot *dq = ip->i_dquot[type];
                    230:        long ncurinodes = dq->dq_curinodes + change;
                    231:
                    232:        KASSERT(mutex_owned(&dq->dq_interlock));
                    233:        /*
                    234:         * If user would exceed their hard limit, disallow inode allocation.
                    235:         */
                    236:        if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
                    237:                if ((dq->dq_flags & DQ_WARN(QL_FILE)) == 0 &&
                    238:                    ip->i_uid == kauth_cred_geteuid(cred)) {
                    239:                        uprintf("\n%s: write failed, %s inode limit reached\n",
                    240:                            ITOV(ip)->v_mount->mnt_stat.f_mntonname,
                    241:                            quotatypes[type]);
                    242:                        dq->dq_flags |= DQ_WARN(QL_FILE);
                    243:                }
                    244:                return (EDQUOT);
                    245:        }
                    246:        /*
                    247:         * If user is over their soft limit for too long, disallow inode
                    248:         * allocation. Reset time limit as they cross their soft limit.
                    249:         */
                    250:        if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
                    251:                if (dq->dq_curinodes < dq->dq_isoftlimit) {
                    252:                        dq->dq_itime =
                    253:                            time_second + ip->i_ump->umq1_itime[type];
                    254:                        if (ip->i_uid == kauth_cred_geteuid(cred))
                    255:                                uprintf("\n%s: warning, %s %s\n",
                    256:                                    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
                    257:                                    quotatypes[type], "inode quota exceeded");
                    258:                        return (0);
                    259:                }
                    260:                if (time_second > dq->dq_itime) {
                    261:                        if ((dq->dq_flags & DQ_WARN(QL_FILE)) == 0 &&
                    262:                            ip->i_uid == kauth_cred_geteuid(cred)) {
                    263:                                uprintf("\n%s: write failed, %s %s\n",
                    264:                                    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
                    265:                                    quotatypes[type],
                    266:                                    "inode quota exceeded for too long");
                    267:                                dq->dq_flags |= DQ_WARN(QL_FILE);
                    268:                        }
                    269:                        return (EDQUOT);
                    270:                }
                    271:        }
                    272:        return (0);
                    273: }
                    274:
                    275: int
                    276: quota1_umount(struct mount *mp, int flags)
                    277: {
                    278:        int i, error;
                    279:        struct ufsmount *ump = VFSTOUFS(mp);
                    280:        struct lwp *l = curlwp;
                    281:
                    282:        if ((ump->um_flags & UFS_QUOTA) == 0)
                    283:                return 0;
                    284:
                    285:        if ((error = vflush(mp, NULLVP, SKIPSYSTEM | flags)) != 0)
                    286:                return (error);
                    287:
                    288:        for (i = 0; i < MAXQUOTAS; i++) {
                    289:                if (ump->um_quotas[i] != NULLVP) {
                    290:                        quota1_handle_cmd_quotaoff(l, ump, i);
                    291:                }
                    292:        }
                    293:        return 0;
                    294: }
                    295:
                    296: /*
                    297:  * Code to process quotactl commands.
                    298:  */
                    299:
                    300: /*
                    301:  * set up a quota file for a particular file system.
                    302:  */
                    303: int
                    304: quota1_handle_cmd_quotaon(struct lwp *l, struct ufsmount *ump, int type,
                    305:     const char *fname)
                    306: {
                    307:        struct mount *mp = ump->um_mountp;
                    308:        struct vnode *vp, **vpp, *mvp;
                    309:        struct dquot *dq;
                    310:        int error;
                    311:        struct pathbuf *pb;
                    312:        struct nameidata nd;
                    313:
                    314:        if (ump->um_flags & UFS_QUOTA2) {
                    315:                uprintf("%s: quotas v2 already enabled\n",
                    316:                    mp->mnt_stat.f_mntonname);
                    317:                return (EBUSY);
                    318:        }
                    319:
                    320:        if (mp->mnt_wapbl != NULL) {
                    321:                printf("%s: quota v1 cannot be used with -o log\n",
                    322:                    mp->mnt_stat.f_mntonname);
                    323:                return (EOPNOTSUPP);
                    324:        }
                    325:
                    326:        vpp = &ump->um_quotas[type];
                    327:
                    328:        pb = pathbuf_create(fname);
                    329:        if (pb == NULL) {
                    330:                return ENOMEM;
                    331:        }
                    332:        NDINIT(&nd, LOOKUP, FOLLOW, pb);
                    333:        if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
                    334:                pathbuf_destroy(pb);
                    335:                return error;
                    336:        }
                    337:        vp = nd.ni_vp;
                    338:        pathbuf_destroy(pb);
                    339:
                    340:        VOP_UNLOCK(vp);
                    341:        if (vp->v_type != VREG) {
                    342:                (void) vn_close(vp, FREAD|FWRITE, l->l_cred);
                    343:                return (EACCES);
                    344:        }
                    345:        if (*vpp != vp)
                    346:                quota1_handle_cmd_quotaoff(l, ump, type);
                    347:        mutex_enter(&dqlock);
                    348:        while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0)
                    349:                cv_wait(&dqcv, &dqlock);
                    350:        ump->umq1_qflags[type] |= QTF_OPENING;
                    351:        mutex_exit(&dqlock);
                    352:        mp->mnt_flag |= MNT_QUOTA;
                    353:        vp->v_vflag |= VV_SYSTEM;       /* XXXSMP */
                    354:        *vpp = vp;
                    355:        /*
                    356:         * Save the credential of the process that turned on quotas.
                    357:         * Set up the time limits for this quota.
                    358:         */
                    359:        kauth_cred_hold(l->l_cred);
                    360:        ump->um_cred[type] = l->l_cred;
                    361:        ump->umq1_btime[type] = MAX_DQ_TIME;
                    362:        ump->umq1_itime[type] = MAX_IQ_TIME;
                    363:        if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
                    364:                if (dq->dq_btime > 0)
                    365:                        ump->umq1_btime[type] = dq->dq_btime;
                    366:                if (dq->dq_itime > 0)
                    367:                        ump->umq1_itime[type] = dq->dq_itime;
                    368:                dqrele(NULLVP, dq);
                    369:        }
                    370:        /* Allocate a marker vnode. */
1.5       hannken   371:        mvp = vnalloc(mp);
1.2       bouyer    372:        /*
                    373:         * Search vnodes associated with this mount point,
                    374:         * adding references to quota file being opened.
                    375:         * NB: only need to add dquot's for inodes being modified.
                    376:         */
                    377:        mutex_enter(&mntvnode_lock);
                    378: again:
                    379:        for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
                    380:                vmark(mvp, vp);
1.4       rmind     381:                mutex_enter(vp->v_interlock);
1.2       bouyer    382:                if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
                    383:                    vp->v_type == VNON || vp->v_writecount == 0 ||
                    384:                    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
1.4       rmind     385:                        mutex_exit(vp->v_interlock);
1.2       bouyer    386:                        continue;
                    387:                }
                    388:                mutex_exit(&mntvnode_lock);
                    389:                if (vget(vp, LK_EXCLUSIVE)) {
                    390:                        mutex_enter(&mntvnode_lock);
                    391:                        (void)vunmark(mvp);
                    392:                        goto again;
                    393:                }
                    394:                if ((error = getinoquota(VTOI(vp))) != 0) {
                    395:                        vput(vp);
                    396:                        mutex_enter(&mntvnode_lock);
                    397:                        (void)vunmark(mvp);
                    398:                        break;
                    399:                }
                    400:                vput(vp);
                    401:                mutex_enter(&mntvnode_lock);
                    402:        }
                    403:        mutex_exit(&mntvnode_lock);
                    404:        vnfree(mvp);
1.5       hannken   405:
1.2       bouyer    406:        mutex_enter(&dqlock);
                    407:        ump->umq1_qflags[type] &= ~QTF_OPENING;
                    408:        cv_broadcast(&dqcv);
                    409:        if (error == 0)
                    410:                ump->um_flags |= UFS_QUOTA;
                    411:        mutex_exit(&dqlock);
                    412:        if (error)
                    413:                quota1_handle_cmd_quotaoff(l, ump, type);
                    414:        return (error);
                    415: }
                    416:
                    417: /*
                    418:  * turn off disk quotas for a filesystem.
                    419:  */
                    420: int
                    421: quota1_handle_cmd_quotaoff(struct lwp *l, struct ufsmount *ump, int type)
                    422: {
                    423:        struct mount *mp = ump->um_mountp;
                    424:        struct vnode *vp;
                    425:        struct vnode *qvp, *mvp;
                    426:        struct dquot *dq;
                    427:        struct inode *ip;
                    428:        kauth_cred_t cred;
                    429:        int i, error;
                    430:
                    431:        /* Allocate a marker vnode. */
1.5       hannken   432:        mvp = vnalloc(mp);
1.2       bouyer    433:
                    434:        mutex_enter(&dqlock);
                    435:        while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0)
                    436:                cv_wait(&dqcv, &dqlock);
                    437:        if ((qvp = ump->um_quotas[type]) == NULLVP) {
                    438:                mutex_exit(&dqlock);
                    439:                vnfree(mvp);
                    440:                return (0);
                    441:        }
                    442:        ump->umq1_qflags[type] |= QTF_CLOSING;
                    443:        ump->um_flags &= ~UFS_QUOTA;
                    444:        mutex_exit(&dqlock);
                    445:        /*
                    446:         * Search vnodes associated with this mount point,
                    447:         * deleting any references to quota file being closed.
                    448:         */
                    449:        mutex_enter(&mntvnode_lock);
                    450: again:
                    451:        for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
                    452:                vmark(mvp, vp);
1.4       rmind     453:                mutex_enter(vp->v_interlock);
1.2       bouyer    454:                if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
                    455:                    vp->v_type == VNON ||
                    456:                    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
1.4       rmind     457:                        mutex_exit(vp->v_interlock);
1.2       bouyer    458:                        continue;
                    459:                }
                    460:                mutex_exit(&mntvnode_lock);
                    461:                if (vget(vp, LK_EXCLUSIVE)) {
                    462:                        mutex_enter(&mntvnode_lock);
                    463:                        (void)vunmark(mvp);
                    464:                        goto again;
                    465:                }
                    466:                ip = VTOI(vp);
                    467:                dq = ip->i_dquot[type];
                    468:                ip->i_dquot[type] = NODQUOT;
                    469:                dqrele(vp, dq);
                    470:                vput(vp);
                    471:                mutex_enter(&mntvnode_lock);
                    472:        }
                    473:        mutex_exit(&mntvnode_lock);
                    474: #ifdef DIAGNOSTIC
                    475:        dqflush(qvp);
                    476: #endif
                    477:        qvp->v_vflag &= ~VV_SYSTEM;
                    478:        error = vn_close(qvp, FREAD|FWRITE, l->l_cred);
                    479:        mutex_enter(&dqlock);
                    480:        ump->um_quotas[type] = NULLVP;
                    481:        cred = ump->um_cred[type];
                    482:        ump->um_cred[type] = NOCRED;
                    483:        for (i = 0; i < MAXQUOTAS; i++)
                    484:                if (ump->um_quotas[i] != NULLVP)
                    485:                        break;
                    486:        ump->umq1_qflags[type] &= ~QTF_CLOSING;
                    487:        cv_broadcast(&dqcv);
                    488:        mutex_exit(&dqlock);
                    489:        kauth_cred_free(cred);
                    490:        if (i == MAXQUOTAS)
                    491:                mp->mnt_flag &= ~MNT_QUOTA;
                    492:        return (error);
                    493: }
                    494:
                    495: int
1.8       dholland  496: quota1_handle_cmd_get(struct ufsmount *ump, int idtype, int id,
1.9     ! dholland  497:     int defaultq, int objtype, struct quotaval *ret)
1.2       bouyer    498: {
                    499:        struct dquot *dq;
                    500:        int error;
1.9     ! dholland  501:        struct quotaval blocks, files;
1.2       bouyer    502:
1.8       dholland  503:        if (ump->um_quotas[idtype] == NULLVP)
1.2       bouyer    504:                return ENODEV;
                    505:
                    506:        if (defaultq) { /* we want the grace period of id 0 */
1.8       dholland  507:                if ((error = dqget(NULLVP, 0, ump, idtype, &dq)) != 0)
1.2       bouyer    508:                        return error;
1.3       bouyer    509:
1.2       bouyer    510:        } else {
1.8       dholland  511:                if ((error = dqget(NULLVP, id, ump, idtype, &dq)) != 0)
1.2       bouyer    512:                        return error;
                    513:        }
1.9     ! dholland  514:        dqblk_to_quotavals(&dq->dq_un.dq1_dqb, &blocks, &files);
1.2       bouyer    515:        dqrele(NULLVP, dq);
                    516:        if (defaultq) {
1.9     ! dholland  517:                if (blocks.qv_expiretime > 0)
        !           518:                        blocks.qv_grace = blocks.qv_expiretime;
1.2       bouyer    519:                else
1.9     ! dholland  520:                        blocks.qv_grace = MAX_DQ_TIME;
        !           521:                if (files.qv_expiretime > 0)
        !           522:                        files.qv_grace = files.qv_expiretime;
1.2       bouyer    523:                else
1.9     ! dholland  524:                        files.qv_grace = MAX_DQ_TIME;
1.2       bouyer    525:        }
1.9     ! dholland  526:
        !           527:        switch (objtype) {
        !           528:            case QUOTA_OBJTYPE_BLOCKS:
        !           529:                *ret = blocks;
        !           530:                break;
        !           531:            case QUOTA_OBJTYPE_FILES:
        !           532:                *ret = files;
        !           533:                break;
        !           534:            default:
        !           535:                return EINVAL;
        !           536:        }
        !           537:
1.2       bouyer    538:        return 0;
                    539: }
                    540:
                    541: int
                    542: quota1_handle_cmd_set(struct ufsmount *ump, int type, int id,
                    543:     int defaultq, prop_dictionary_t data)
                    544: {
                    545:        struct dquot *dq;
                    546:        struct dqblk dqb;
                    547:        int error;
1.3       bouyer    548:        uint64_t bval[2];
                    549:        uint64_t ival[2];
                    550:        const char *val_limitsonly_grace[] = {QUOTADICT_LIMIT_GTIME};
                    551: #define Q1_GTIME 0
                    552:        const char *val_limitsonly_softhard[] =
                    553:            {QUOTADICT_LIMIT_SOFT, QUOTADICT_LIMIT_HARD};
                    554: #define Q1_SOFT 0
                    555: #define Q1_HARD 1
                    556:
                    557:        uint64_t *valuesp[QUOTA_NLIMITS];
                    558:        valuesp[QUOTA_LIMIT_BLOCK] = bval;
                    559:        valuesp[QUOTA_LIMIT_FILE] = ival;
1.2       bouyer    560:
                    561:        if (ump->um_quotas[type] == NULLVP)
                    562:                return ENODEV;
                    563:
                    564:        if (defaultq) {
                    565:                /* just update grace times */
1.3       bouyer    566:                error = proptoquota64(data, valuesp, val_limitsonly_grace, 1,
                    567:                    ufs_quota_limit_names, QUOTA_NLIMITS);
                    568:                if (error)
                    569:                        return error;
1.2       bouyer    570:                if ((error = dqget(NULLVP, id, ump, type, &dq)) != 0)
                    571:                        return error;
                    572:                mutex_enter(&dq->dq_interlock);
1.3       bouyer    573:                if (bval[Q1_GTIME] > 0)
1.2       bouyer    574:                        ump->umq1_btime[type] = dq->dq_btime =
1.3       bouyer    575:                            bval[Q1_GTIME];
                    576:                if (ival[Q1_GTIME] > 0)
1.2       bouyer    577:                        ump->umq1_itime[type] = dq->dq_itime =
1.3       bouyer    578:                            ival[Q1_GTIME];
1.2       bouyer    579:                mutex_exit(&dq->dq_interlock);
                    580:                dq->dq_flags |= DQ_MOD;
                    581:                dqrele(NULLVP, dq);
                    582:                return 0;
                    583:        }
1.3       bouyer    584:        error = proptoquota64(data, valuesp, val_limitsonly_softhard, 2,
                    585:            ufs_quota_limit_names, QUOTA_NLIMITS);
                    586:        if (error)
                    587:                return error;
1.2       bouyer    588:
                    589:        if ((error = dqget(NULLVP, id, ump, type, &dq)) != 0)
                    590:                return (error);
                    591:        mutex_enter(&dq->dq_interlock);
                    592:        /*
                    593:         * Copy all but the current values.
                    594:         * Reset time limit if previously had no soft limit or were
                    595:         * under it, but now have a soft limit and are over it.
                    596:         */
                    597:        dqb.dqb_curblocks = dq->dq_curblocks;
                    598:        dqb.dqb_curinodes = dq->dq_curinodes;
1.3       bouyer    599:        dqb.dqb_btime = dq->dq_btime;
                    600:        dqb.dqb_itime = dq->dq_itime;
                    601:        dqb.dqb_bsoftlimit = (bval[Q1_SOFT] == UQUAD_MAX) ? 0 : bval[Q1_SOFT];
                    602:        dqb.dqb_bhardlimit = (bval[Q1_HARD] == UQUAD_MAX) ? 0 : bval[Q1_HARD];
                    603:        dqb.dqb_isoftlimit = (ival[Q1_SOFT] == UQUAD_MAX) ? 0 : ival[Q1_SOFT];
                    604:        dqb.dqb_ihardlimit = (ival[Q1_HARD] == UQUAD_MAX) ? 0 : ival[Q1_HARD];
                    605:        if (dq->dq_id == 0) {
                    606:                /* also update grace time if available */
                    607:                if (proptoquota64(data, valuesp, val_limitsonly_grace, 1,
                    608:                    ufs_quota_limit_names, QUOTA_NLIMITS) == 0) {
                    609:                        if (bval[Q1_GTIME] > 0)
                    610:                                ump->umq1_btime[type] = dqb.dqb_btime =
                    611:                                    bval[Q1_GTIME];
                    612:                        if (ival[Q1_GTIME] > 0)
                    613:                                ump->umq1_itime[type] = dqb.dqb_itime =
                    614:                                    ival[Q1_GTIME];
                    615:                }
1.2       bouyer    616:        }
                    617:        if (dqb.dqb_bsoftlimit &&
                    618:            dq->dq_curblocks >= dqb.dqb_bsoftlimit &&
                    619:            (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
                    620:                dqb.dqb_btime = time_second + ump->umq1_btime[type];
                    621:        if (dqb.dqb_isoftlimit &&
                    622:            dq->dq_curinodes >= dqb.dqb_isoftlimit &&
                    623:            (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
                    624:                dqb.dqb_itime = time_second + ump->umq1_itime[type];
                    625:        dq->dq_un.dq1_dqb = dqb;
                    626:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
                    627:                dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                    628:        if (dq->dq_curinodes < dq->dq_isoftlimit)
                    629:                dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    630:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
                    631:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
                    632:                dq->dq_flags |= DQ_FAKE;
                    633:        else
                    634:                dq->dq_flags &= ~DQ_FAKE;
                    635:        dq->dq_flags |= DQ_MOD;
                    636:        mutex_exit(&dq->dq_interlock);
                    637:        dqrele(NULLVP, dq);
                    638:        return (0);
                    639: }
                    640:
                    641:
                    642: #if 0
                    643: /*
                    644:  * Q_SETQUOTA - assign an entire dqblk structure.
                    645:  */
                    646: int
                    647: setquota1(struct mount *mp, u_long id, int type, struct dqblk *dqb)
                    648: {
                    649:        struct dquot *dq;
                    650:        struct dquot *ndq;
                    651:        struct ufsmount *ump = VFSTOUFS(mp);
                    652:
                    653:
                    654:        if ((error = dqget(NULLVP, id, ump, type, &ndq)) != 0)
                    655:                return (error);
                    656:        dq = ndq;
                    657:        mutex_enter(&dq->dq_interlock);
                    658:        /*
                    659:         * Copy all but the current values.
                    660:         * Reset time limit if previously had no soft limit or were
                    661:         * under it, but now have a soft limit and are over it.
                    662:         */
                    663:        dqb->dqb_curblocks = dq->dq_curblocks;
                    664:        dqb->dqb_curinodes = dq->dq_curinodes;
                    665:        if (dq->dq_id != 0) {
                    666:                dqb->dqb_btime = dq->dq_btime;
                    667:                dqb->dqb_itime = dq->dq_itime;
                    668:        }
                    669:        if (dqb->dqb_bsoftlimit &&
                    670:            dq->dq_curblocks >= dqb->dqb_bsoftlimit &&
                    671:            (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
                    672:                dqb->dqb_btime = time_second + ump->umq1_btime[type];
                    673:        if (dqb->dqb_isoftlimit &&
                    674:            dq->dq_curinodes >= dqb->dqb_isoftlimit &&
                    675:            (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
                    676:                dqb->dqb_itime = time_second + ump->umq1_itime[type];
                    677:        dq->dq_un.dq1_dqb = *dqb;
                    678:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
                    679:                dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                    680:        if (dq->dq_curinodes < dq->dq_isoftlimit)
                    681:                dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    682:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
                    683:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
                    684:                dq->dq_flags |= DQ_FAKE;
                    685:        else
                    686:                dq->dq_flags &= ~DQ_FAKE;
                    687:        dq->dq_flags |= DQ_MOD;
                    688:        mutex_exit(&dq->dq_interlock);
                    689:        dqrele(NULLVP, dq);
                    690:        return (0);
                    691: }
                    692:
                    693: /*
                    694:  * Q_SETUSE - set current inode and block usage.
                    695:  */
                    696: int
                    697: setuse(struct mount *mp, u_long id, int type, void *addr)
                    698: {
                    699:        struct dquot *dq;
                    700:        struct ufsmount *ump = VFSTOUFS(mp);
                    701:        struct dquot *ndq;
                    702:        struct dqblk usage;
                    703:        int error;
                    704:
                    705:        error = copyin(addr, (void *)&usage, sizeof (struct dqblk));
                    706:        if (error)
                    707:                return (error);
                    708:        if ((error = dqget(NULLVP, id, ump, type, &ndq)) != 0)
                    709:                return (error);
                    710:        dq = ndq;
                    711:        mutex_enter(&dq->dq_interlock);
                    712:        /*
                    713:         * Reset time limit if have a soft limit and were
                    714:         * previously under it, but are now over it.
                    715:         */
                    716:        if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
                    717:            usage.dqb_curblocks >= dq->dq_bsoftlimit)
                    718:                dq->dq_btime = time_second + ump->umq1_btime[type];
                    719:        if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
                    720:            usage.dqb_curinodes >= dq->dq_isoftlimit)
                    721:                dq->dq_itime = time_second + ump->umq1_itime[type];
                    722:        dq->dq_curblocks = usage.dqb_curblocks;
                    723:        dq->dq_curinodes = usage.dqb_curinodes;
                    724:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
                    725:                dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                    726:        if (dq->dq_curinodes < dq->dq_isoftlimit)
                    727:                dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    728:        dq->dq_flags |= DQ_MOD;
                    729:        mutex_exit(&dq->dq_interlock);
                    730:        dqrele(NULLVP, dq);
                    731:        return (0);
                    732: }
                    733: #endif
                    734:
                    735: /*
                    736:  * Q_SYNC - sync quota files to disk.
                    737:  */
                    738: int
                    739: q1sync(struct mount *mp)
                    740: {
                    741:        struct ufsmount *ump = VFSTOUFS(mp);
                    742:        struct vnode *vp, *mvp;
                    743:        struct dquot *dq;
                    744:        int i, error;
                    745:
                    746:        /*
                    747:         * Check if the mount point has any quotas.
                    748:         * If not, simply return.
                    749:         */
                    750:        for (i = 0; i < MAXQUOTAS; i++)
                    751:                if (ump->um_quotas[i] != NULLVP)
                    752:                        break;
                    753:        if (i == MAXQUOTAS)
                    754:                return (0);
                    755:
                    756:        /* Allocate a marker vnode. */
1.5       hannken   757:        mvp = vnalloc(mp);
1.2       bouyer    758:
                    759:        /*
                    760:         * Search vnodes associated with this mount point,
                    761:         * synchronizing any modified dquot structures.
                    762:         */
                    763:        mutex_enter(&mntvnode_lock);
                    764:  again:
                    765:        for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
                    766:                vmark(mvp, vp);
1.4       rmind     767:                mutex_enter(vp->v_interlock);
1.2       bouyer    768:                if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
                    769:                    vp->v_type == VNON ||
                    770:                    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
1.4       rmind     771:                        mutex_exit(vp->v_interlock);
1.2       bouyer    772:                        continue;
                    773:                }
                    774:                mutex_exit(&mntvnode_lock);
                    775:                error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
                    776:                if (error) {
                    777:                        mutex_enter(&mntvnode_lock);
                    778:                        if (error == ENOENT) {
                    779:                                (void)vunmark(mvp);
                    780:                                goto again;
                    781:                        }
                    782:                        continue;
                    783:                }
                    784:                for (i = 0; i < MAXQUOTAS; i++) {
                    785:                        dq = VTOI(vp)->i_dquot[i];
                    786:                        if (dq == NODQUOT)
                    787:                                continue;
                    788:                        mutex_enter(&dq->dq_interlock);
                    789:                        if (dq->dq_flags & DQ_MOD)
                    790:                                dq1sync(vp, dq);
                    791:                        mutex_exit(&dq->dq_interlock);
                    792:                }
                    793:                vput(vp);
                    794:                mutex_enter(&mntvnode_lock);
                    795:        }
                    796:        mutex_exit(&mntvnode_lock);
                    797:        vnfree(mvp);
                    798:        return (0);
                    799: }
                    800:
                    801: /*
                    802:  * Obtain a dquot structure for the specified identifier and quota file
                    803:  * reading the information from the file if necessary.
                    804:  */
                    805: int
                    806: dq1get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
                    807:     struct dquot *dq)
                    808: {
                    809:        struct iovec aiov;
                    810:        struct uio auio;
                    811:        int error;
                    812:
                    813:        KASSERT(mutex_owned(&dq->dq_interlock));
                    814:        vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
                    815:        auio.uio_iov = &aiov;
                    816:        auio.uio_iovcnt = 1;
                    817:        aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
                    818:        aiov.iov_len = sizeof (struct dqblk);
                    819:        auio.uio_resid = sizeof (struct dqblk);
                    820:        auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
                    821:        auio.uio_rw = UIO_READ;
                    822:        UIO_SETUP_SYSSPACE(&auio);
                    823:        error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
                    824:        if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
                    825:                memset((void *)&dq->dq_un.dq1_dqb, 0, sizeof(struct dqblk));
                    826:        VOP_UNLOCK(dqvp);
                    827:        /*
                    828:         * I/O error in reading quota file, release
                    829:         * quota structure and reflect problem to caller.
                    830:         */
                    831:        if (error)
                    832:                return (error);
                    833:        /*
                    834:         * Check for no limit to enforce.
                    835:         * Initialize time values if necessary.
                    836:         */
                    837:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
                    838:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
                    839:                dq->dq_flags |= DQ_FAKE;
                    840:        if (dq->dq_id != 0) {
                    841:                if (dq->dq_btime == 0)
                    842:                        dq->dq_btime = time_second + ump->umq1_btime[type];
                    843:                if (dq->dq_itime == 0)
                    844:                        dq->dq_itime = time_second + ump->umq1_itime[type];
                    845:        }
                    846:        return (0);
                    847: }
                    848:
                    849: /*
                    850:  * Update the disk quota in the quota file.
                    851:  */
                    852: int
                    853: dq1sync(struct vnode *vp, struct dquot *dq)
                    854: {
                    855:        struct vnode *dqvp;
                    856:        struct iovec aiov;
                    857:        struct uio auio;
                    858:        int error;
                    859:
                    860:        if (dq == NODQUOT)
                    861:                panic("dq1sync: dquot");
                    862:        KASSERT(mutex_owned(&dq->dq_interlock));
                    863:        if ((dq->dq_flags & DQ_MOD) == 0)
                    864:                return (0);
                    865:        if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
                    866:                panic("dq1sync: file");
                    867:        KASSERT(dqvp != vp);
                    868:        vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
                    869:        auio.uio_iov = &aiov;
                    870:        auio.uio_iovcnt = 1;
                    871:        aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
                    872:        aiov.iov_len = sizeof (struct dqblk);
                    873:        auio.uio_resid = sizeof (struct dqblk);
                    874:        auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
                    875:        auio.uio_rw = UIO_WRITE;
                    876:        UIO_SETUP_SYSSPACE(&auio);
                    877:        error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
                    878:        if (auio.uio_resid && error == 0)
                    879:                error = EIO;
                    880:        dq->dq_flags &= ~DQ_MOD;
                    881:        VOP_UNLOCK(dqvp);
                    882:        return (error);
                    883: }

CVSweb <webmaster@jp.NetBSD.org>