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

1.5     ! hannken     1: /*     $NetBSD: ufs_quota1.c,v 1.4 2011/06/12 03:36:02 rmind 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.5     ! hannken    38: __KERNEL_RCSID(0, "$NetBSD: ufs_quota1.c,v 1.4 2011/06/12 03:36:02 rmind 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
                    496: quota1_handle_cmd_get(struct ufsmount *ump, int type, int id,
                    497:     int defaultq, prop_array_t replies)
                    498: {
                    499:        struct dquot *dq;
1.3       bouyer    500:        struct ufs_quota_entry qe[QUOTA_NLIMITS];
1.2       bouyer    501:        prop_dictionary_t dict;
                    502:        int error;
1.3       bouyer    503:        uint64_t *valuesp[QUOTA_NLIMITS];
                    504:        valuesp[QUOTA_LIMIT_BLOCK] = &qe[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit;
                    505:        valuesp[QUOTA_LIMIT_FILE] = &qe[QUOTA_LIMIT_FILE].ufsqe_hardlimit;
                    506:
1.2       bouyer    507:
                    508:        if (ump->um_quotas[type] == NULLVP)
                    509:                return ENODEV;
                    510:
                    511:        if (defaultq) { /* we want the grace period of id 0 */
                    512:                if ((error = dqget(NULLVP, 0, ump, type, &dq)) != 0)
                    513:                        return error;
1.3       bouyer    514:
1.2       bouyer    515:        } else {
                    516:                if ((error = dqget(NULLVP, id, ump, type, &dq)) != 0)
                    517:                        return error;
                    518:        }
1.3       bouyer    519:        dqblk2ufsqe(&dq->dq_un.dq1_dqb, qe);
1.2       bouyer    520:        dqrele(NULLVP, dq);
                    521:        if (defaultq) {
1.3       bouyer    522:                if (qe[QUOTA_LIMIT_BLOCK].ufsqe_time > 0)
                    523:                        qe[QUOTA_LIMIT_BLOCK].ufsqe_grace =
                    524:                            qe[QUOTA_LIMIT_BLOCK].ufsqe_time;
1.2       bouyer    525:                else
1.3       bouyer    526:                        qe[QUOTA_LIMIT_BLOCK].ufsqe_grace = MAX_DQ_TIME;
                    527:                if (qe[QUOTA_LIMIT_FILE].ufsqe_time > 0)
                    528:                        qe[QUOTA_LIMIT_FILE].ufsqe_grace =
                    529:                            qe[QUOTA_LIMIT_FILE].ufsqe_time;
1.2       bouyer    530:                else
1.3       bouyer    531:                        qe[QUOTA_LIMIT_FILE].ufsqe_grace = MAX_DQ_TIME;
1.2       bouyer    532:        }
1.3       bouyer    533:        dict = quota64toprop(id, defaultq, valuesp,
                    534:            ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
                    535:            ufs_quota_limit_names, QUOTA_NLIMITS);
1.2       bouyer    536:        if (dict == NULL)
                    537:                return ENOMEM;
                    538:        if (!prop_array_add_and_rel(replies, dict))
                    539:                return ENOMEM;
                    540:        return 0;
                    541: }
                    542:
                    543: int
                    544: quota1_handle_cmd_set(struct ufsmount *ump, int type, int id,
                    545:     int defaultq, prop_dictionary_t data)
                    546: {
                    547:        struct dquot *dq;
                    548:        struct dqblk dqb;
                    549:        int error;
1.3       bouyer    550:        uint64_t bval[2];
                    551:        uint64_t ival[2];
                    552:        const char *val_limitsonly_grace[] = {QUOTADICT_LIMIT_GTIME};
                    553: #define Q1_GTIME 0
                    554:        const char *val_limitsonly_softhard[] =
                    555:            {QUOTADICT_LIMIT_SOFT, QUOTADICT_LIMIT_HARD};
                    556: #define Q1_SOFT 0
                    557: #define Q1_HARD 1
                    558:
                    559:        uint64_t *valuesp[QUOTA_NLIMITS];
                    560:        valuesp[QUOTA_LIMIT_BLOCK] = bval;
                    561:        valuesp[QUOTA_LIMIT_FILE] = ival;
1.2       bouyer    562:
                    563:        if (ump->um_quotas[type] == NULLVP)
                    564:                return ENODEV;
                    565:
                    566:        if (defaultq) {
                    567:                /* just update grace times */
1.3       bouyer    568:                error = proptoquota64(data, valuesp, val_limitsonly_grace, 1,
                    569:                    ufs_quota_limit_names, QUOTA_NLIMITS);
                    570:                if (error)
                    571:                        return error;
1.2       bouyer    572:                if ((error = dqget(NULLVP, id, ump, type, &dq)) != 0)
                    573:                        return error;
                    574:                mutex_enter(&dq->dq_interlock);
1.3       bouyer    575:                if (bval[Q1_GTIME] > 0)
1.2       bouyer    576:                        ump->umq1_btime[type] = dq->dq_btime =
1.3       bouyer    577:                            bval[Q1_GTIME];
                    578:                if (ival[Q1_GTIME] > 0)
1.2       bouyer    579:                        ump->umq1_itime[type] = dq->dq_itime =
1.3       bouyer    580:                            ival[Q1_GTIME];
1.2       bouyer    581:                mutex_exit(&dq->dq_interlock);
                    582:                dq->dq_flags |= DQ_MOD;
                    583:                dqrele(NULLVP, dq);
                    584:                return 0;
                    585:        }
1.3       bouyer    586:        error = proptoquota64(data, valuesp, val_limitsonly_softhard, 2,
                    587:            ufs_quota_limit_names, QUOTA_NLIMITS);
                    588:        if (error)
                    589:                return error;
1.2       bouyer    590:
                    591:        if ((error = dqget(NULLVP, id, ump, type, &dq)) != 0)
                    592:                return (error);
                    593:        mutex_enter(&dq->dq_interlock);
                    594:        /*
                    595:         * Copy all but the current values.
                    596:         * Reset time limit if previously had no soft limit or were
                    597:         * under it, but now have a soft limit and are over it.
                    598:         */
                    599:        dqb.dqb_curblocks = dq->dq_curblocks;
                    600:        dqb.dqb_curinodes = dq->dq_curinodes;
1.3       bouyer    601:        dqb.dqb_btime = dq->dq_btime;
                    602:        dqb.dqb_itime = dq->dq_itime;
                    603:        dqb.dqb_bsoftlimit = (bval[Q1_SOFT] == UQUAD_MAX) ? 0 : bval[Q1_SOFT];
                    604:        dqb.dqb_bhardlimit = (bval[Q1_HARD] == UQUAD_MAX) ? 0 : bval[Q1_HARD];
                    605:        dqb.dqb_isoftlimit = (ival[Q1_SOFT] == UQUAD_MAX) ? 0 : ival[Q1_SOFT];
                    606:        dqb.dqb_ihardlimit = (ival[Q1_HARD] == UQUAD_MAX) ? 0 : ival[Q1_HARD];
                    607:        if (dq->dq_id == 0) {
                    608:                /* also update grace time if available */
                    609:                if (proptoquota64(data, valuesp, val_limitsonly_grace, 1,
                    610:                    ufs_quota_limit_names, QUOTA_NLIMITS) == 0) {
                    611:                        if (bval[Q1_GTIME] > 0)
                    612:                                ump->umq1_btime[type] = dqb.dqb_btime =
                    613:                                    bval[Q1_GTIME];
                    614:                        if (ival[Q1_GTIME] > 0)
                    615:                                ump->umq1_itime[type] = dqb.dqb_itime =
                    616:                                    ival[Q1_GTIME];
                    617:                }
1.2       bouyer    618:        }
                    619:        if (dqb.dqb_bsoftlimit &&
                    620:            dq->dq_curblocks >= dqb.dqb_bsoftlimit &&
                    621:            (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
                    622:                dqb.dqb_btime = time_second + ump->umq1_btime[type];
                    623:        if (dqb.dqb_isoftlimit &&
                    624:            dq->dq_curinodes >= dqb.dqb_isoftlimit &&
                    625:            (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
                    626:                dqb.dqb_itime = time_second + ump->umq1_itime[type];
                    627:        dq->dq_un.dq1_dqb = dqb;
                    628:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
                    629:                dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                    630:        if (dq->dq_curinodes < dq->dq_isoftlimit)
                    631:                dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    632:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
                    633:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
                    634:                dq->dq_flags |= DQ_FAKE;
                    635:        else
                    636:                dq->dq_flags &= ~DQ_FAKE;
                    637:        dq->dq_flags |= DQ_MOD;
                    638:        mutex_exit(&dq->dq_interlock);
                    639:        dqrele(NULLVP, dq);
                    640:        return (0);
                    641: }
                    642:
                    643:
                    644: #if 0
                    645: /*
                    646:  * Q_SETQUOTA - assign an entire dqblk structure.
                    647:  */
                    648: int
                    649: setquota1(struct mount *mp, u_long id, int type, struct dqblk *dqb)
                    650: {
                    651:        struct dquot *dq;
                    652:        struct dquot *ndq;
                    653:        struct ufsmount *ump = VFSTOUFS(mp);
                    654:
                    655:
                    656:        if ((error = dqget(NULLVP, id, ump, type, &ndq)) != 0)
                    657:                return (error);
                    658:        dq = ndq;
                    659:        mutex_enter(&dq->dq_interlock);
                    660:        /*
                    661:         * Copy all but the current values.
                    662:         * Reset time limit if previously had no soft limit or were
                    663:         * under it, but now have a soft limit and are over it.
                    664:         */
                    665:        dqb->dqb_curblocks = dq->dq_curblocks;
                    666:        dqb->dqb_curinodes = dq->dq_curinodes;
                    667:        if (dq->dq_id != 0) {
                    668:                dqb->dqb_btime = dq->dq_btime;
                    669:                dqb->dqb_itime = dq->dq_itime;
                    670:        }
                    671:        if (dqb->dqb_bsoftlimit &&
                    672:            dq->dq_curblocks >= dqb->dqb_bsoftlimit &&
                    673:            (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
                    674:                dqb->dqb_btime = time_second + ump->umq1_btime[type];
                    675:        if (dqb->dqb_isoftlimit &&
                    676:            dq->dq_curinodes >= dqb->dqb_isoftlimit &&
                    677:            (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
                    678:                dqb->dqb_itime = time_second + ump->umq1_itime[type];
                    679:        dq->dq_un.dq1_dqb = *dqb;
                    680:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
                    681:                dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                    682:        if (dq->dq_curinodes < dq->dq_isoftlimit)
                    683:                dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    684:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
                    685:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
                    686:                dq->dq_flags |= DQ_FAKE;
                    687:        else
                    688:                dq->dq_flags &= ~DQ_FAKE;
                    689:        dq->dq_flags |= DQ_MOD;
                    690:        mutex_exit(&dq->dq_interlock);
                    691:        dqrele(NULLVP, dq);
                    692:        return (0);
                    693: }
                    694:
                    695: /*
                    696:  * Q_SETUSE - set current inode and block usage.
                    697:  */
                    698: int
                    699: setuse(struct mount *mp, u_long id, int type, void *addr)
                    700: {
                    701:        struct dquot *dq;
                    702:        struct ufsmount *ump = VFSTOUFS(mp);
                    703:        struct dquot *ndq;
                    704:        struct dqblk usage;
                    705:        int error;
                    706:
                    707:        error = copyin(addr, (void *)&usage, sizeof (struct dqblk));
                    708:        if (error)
                    709:                return (error);
                    710:        if ((error = dqget(NULLVP, id, ump, type, &ndq)) != 0)
                    711:                return (error);
                    712:        dq = ndq;
                    713:        mutex_enter(&dq->dq_interlock);
                    714:        /*
                    715:         * Reset time limit if have a soft limit and were
                    716:         * previously under it, but are now over it.
                    717:         */
                    718:        if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
                    719:            usage.dqb_curblocks >= dq->dq_bsoftlimit)
                    720:                dq->dq_btime = time_second + ump->umq1_btime[type];
                    721:        if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
                    722:            usage.dqb_curinodes >= dq->dq_isoftlimit)
                    723:                dq->dq_itime = time_second + ump->umq1_itime[type];
                    724:        dq->dq_curblocks = usage.dqb_curblocks;
                    725:        dq->dq_curinodes = usage.dqb_curinodes;
                    726:        if (dq->dq_curblocks < dq->dq_bsoftlimit)
                    727:                dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
                    728:        if (dq->dq_curinodes < dq->dq_isoftlimit)
                    729:                dq->dq_flags &= ~DQ_WARN(QL_FILE);
                    730:        dq->dq_flags |= DQ_MOD;
                    731:        mutex_exit(&dq->dq_interlock);
                    732:        dqrele(NULLVP, dq);
                    733:        return (0);
                    734: }
                    735: #endif
                    736:
                    737: /*
                    738:  * Q_SYNC - sync quota files to disk.
                    739:  */
                    740: int
                    741: q1sync(struct mount *mp)
                    742: {
                    743:        struct ufsmount *ump = VFSTOUFS(mp);
                    744:        struct vnode *vp, *mvp;
                    745:        struct dquot *dq;
                    746:        int i, error;
                    747:
                    748:        /*
                    749:         * Check if the mount point has any quotas.
                    750:         * If not, simply return.
                    751:         */
                    752:        for (i = 0; i < MAXQUOTAS; i++)
                    753:                if (ump->um_quotas[i] != NULLVP)
                    754:                        break;
                    755:        if (i == MAXQUOTAS)
                    756:                return (0);
                    757:
                    758:        /* Allocate a marker vnode. */
1.5     ! hannken   759:        mvp = vnalloc(mp);
1.2       bouyer    760:
                    761:        /*
                    762:         * Search vnodes associated with this mount point,
                    763:         * synchronizing any modified dquot structures.
                    764:         */
                    765:        mutex_enter(&mntvnode_lock);
                    766:  again:
                    767:        for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
                    768:                vmark(mvp, vp);
1.4       rmind     769:                mutex_enter(vp->v_interlock);
1.2       bouyer    770:                if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
                    771:                    vp->v_type == VNON ||
                    772:                    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
1.4       rmind     773:                        mutex_exit(vp->v_interlock);
1.2       bouyer    774:                        continue;
                    775:                }
                    776:                mutex_exit(&mntvnode_lock);
                    777:                error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
                    778:                if (error) {
                    779:                        mutex_enter(&mntvnode_lock);
                    780:                        if (error == ENOENT) {
                    781:                                (void)vunmark(mvp);
                    782:                                goto again;
                    783:                        }
                    784:                        continue;
                    785:                }
                    786:                for (i = 0; i < MAXQUOTAS; i++) {
                    787:                        dq = VTOI(vp)->i_dquot[i];
                    788:                        if (dq == NODQUOT)
                    789:                                continue;
                    790:                        mutex_enter(&dq->dq_interlock);
                    791:                        if (dq->dq_flags & DQ_MOD)
                    792:                                dq1sync(vp, dq);
                    793:                        mutex_exit(&dq->dq_interlock);
                    794:                }
                    795:                vput(vp);
                    796:                mutex_enter(&mntvnode_lock);
                    797:        }
                    798:        mutex_exit(&mntvnode_lock);
                    799:        vnfree(mvp);
                    800:        return (0);
                    801: }
                    802:
                    803: /*
                    804:  * Obtain a dquot structure for the specified identifier and quota file
                    805:  * reading the information from the file if necessary.
                    806:  */
                    807: int
                    808: dq1get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
                    809:     struct dquot *dq)
                    810: {
                    811:        struct iovec aiov;
                    812:        struct uio auio;
                    813:        int error;
                    814:
                    815:        KASSERT(mutex_owned(&dq->dq_interlock));
                    816:        vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
                    817:        auio.uio_iov = &aiov;
                    818:        auio.uio_iovcnt = 1;
                    819:        aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
                    820:        aiov.iov_len = sizeof (struct dqblk);
                    821:        auio.uio_resid = sizeof (struct dqblk);
                    822:        auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
                    823:        auio.uio_rw = UIO_READ;
                    824:        UIO_SETUP_SYSSPACE(&auio);
                    825:        error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
                    826:        if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
                    827:                memset((void *)&dq->dq_un.dq1_dqb, 0, sizeof(struct dqblk));
                    828:        VOP_UNLOCK(dqvp);
                    829:        /*
                    830:         * I/O error in reading quota file, release
                    831:         * quota structure and reflect problem to caller.
                    832:         */
                    833:        if (error)
                    834:                return (error);
                    835:        /*
                    836:         * Check for no limit to enforce.
                    837:         * Initialize time values if necessary.
                    838:         */
                    839:        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
                    840:            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
                    841:                dq->dq_flags |= DQ_FAKE;
                    842:        if (dq->dq_id != 0) {
                    843:                if (dq->dq_btime == 0)
                    844:                        dq->dq_btime = time_second + ump->umq1_btime[type];
                    845:                if (dq->dq_itime == 0)
                    846:                        dq->dq_itime = time_second + ump->umq1_itime[type];
                    847:        }
                    848:        return (0);
                    849: }
                    850:
                    851: /*
                    852:  * Update the disk quota in the quota file.
                    853:  */
                    854: int
                    855: dq1sync(struct vnode *vp, struct dquot *dq)
                    856: {
                    857:        struct vnode *dqvp;
                    858:        struct iovec aiov;
                    859:        struct uio auio;
                    860:        int error;
                    861:
                    862:        if (dq == NODQUOT)
                    863:                panic("dq1sync: dquot");
                    864:        KASSERT(mutex_owned(&dq->dq_interlock));
                    865:        if ((dq->dq_flags & DQ_MOD) == 0)
                    866:                return (0);
                    867:        if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
                    868:                panic("dq1sync: file");
                    869:        KASSERT(dqvp != vp);
                    870:        vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
                    871:        auio.uio_iov = &aiov;
                    872:        auio.uio_iovcnt = 1;
                    873:        aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
                    874:        aiov.iov_len = sizeof (struct dqblk);
                    875:        auio.uio_resid = sizeof (struct dqblk);
                    876:        auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
                    877:        auio.uio_rw = UIO_WRITE;
                    878:        UIO_SETUP_SYSSPACE(&auio);
                    879:        error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
                    880:        if (auio.uio_resid && error == 0)
                    881:                error = EIO;
                    882:        dq->dq_flags &= ~DQ_MOD;
                    883:        VOP_UNLOCK(dqvp);
                    884:        return (error);
                    885: }

CVSweb <webmaster@jp.NetBSD.org>