/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * @(#)quota_ufs.c 7.1.1 (2.11BSD GTE) 12/31/93 */ /* * MELBOURNE QUOTAS * * Routines used in checking limits on file system usage. */ #include "param.h" #ifdef QUOTA #include "systm.h" #include "user.h" #include "proc.h" #include "inode.h" #include "quota.h" #include "fs.h" #include "mount.h" #include "uio.h" /* * Find the dquot structure that should * be used in checking i/o on inode ip. */ struct dquot * inoquota(ip) register struct inode *ip; { register struct quota *q; register struct dquot **dqq; register struct mount *mp; int index; top: q = qfind(ip->i_uid); if (q == NOQUOTA) { for (mp = mount; mp < &mount[NMOUNT]; mp++) #ifdef pdp11 if (mp->m_inodp && mp->m_dev == ip->i_dev) #else if (mp->m_bufp && mp->m_dev == ip->i_dev) #endif return (discquota(ip->i_uid, mp->m_qinod)); panic("inoquota"); } /* * We have a quota struct in core (most likely our own) that * belongs to the same user as the inode */ if (q->q_flags & Q_NDQ) return (NODQUOT); if (q->q_flags & Q_LOCK) { q->q_flags |= Q_WANT; #ifdef pdp11 QUOTAUNMAP(); sleep((caddr_t)q, PINOD+1); QUOTAMAP(); #else sleep((caddr_t)q, PINOD+1); #endif goto top; /* might just have been freed */ } index = getfsx(ip->i_dev); dqq = &q->q_dq[index]; if (*dqq == LOSTDQUOT) { q->q_flags |= Q_LOCK; *dqq = discquota(q->q_uid, mount[index].m_qinod); if (*dqq != NODQUOT) (*dqq)->dq_own = q; if (q->q_flags & Q_WANT) wakeup((caddr_t)q); q->q_flags &= ~(Q_LOCK | Q_WANT); } if (*dqq != NODQUOT) (*dqq)->dq_cnt++; return (*dqq); } /* * Update disc usage, and take corrective action. */ chkdq(ip, change, force) register struct inode *ip; long change; int force; { register struct dquot *dq; if (change == 0) return (0); #ifdef pdp11 dq = ix_dquot[ip - inode]; #else dq = ip->i_dquot; #endif if (dq == NODQUOT) return (0); if (dq->dq_bsoftlimit == 0) return (0); dq->dq_flags |= DQ_MOD; /* * reset warnings if below disk quota. */ if (dq->dq_bwarn == 0 && dq->dq_bsoftlimit && (dq->dq_curblocks + change) < dq->dq_bsoftlimit) { dq->dq_bwarn = MAX_DQ_WARN; if (dq->dq_own == u.u_quota) { uprintf("\nUNDER DISC QUOTA: (%s) by %d Kbytes\n", ip->i_fs->fs_fsmnt, #ifdef pdp11 (dq->dq_bsoftlimit + 1023L - (dq->dq_curblocks + change)) / 1024); #else dbtob(dq->dq_bsoftlimit - (dq->dq_curblocks + change)) / 1024); #endif } } if (change < 0) { if (dq->dq_curblocks + change >= 0) dq->dq_curblocks += change; else dq->dq_curblocks = 0; dq->dq_flags &= ~DQ_BLKS; return (0); } /* * If user is over quota, or has run out of warnings, then * disallow space allocation (except su's are never stopped). */ if (u.u_uid == 0) force = 1; if (!force && dq->dq_bwarn == 0) { if ((dq->dq_flags & DQ_BLKS) == 0 && dq->dq_own == u.u_quota) { uprintf("\nOVER DISC QUOTA: (%s) NO MORE DISC SPACE\n", ip->i_fs->fs_fsmnt); dq->dq_flags |= DQ_BLKS; } return (EDQUOT); } if (dq->dq_curblocks < dq->dq_bsoftlimit) { dq->dq_curblocks += change; if (dq->dq_curblocks < dq->dq_bsoftlimit) return (0); if (dq->dq_own == u.u_quota) uprintf("\nWARNING: disc quota (%s) exceeded\n", ip->i_fs->fs_fsmnt); return (0); } if (!force && dq->dq_bhardlimit && dq->dq_curblocks + change >= dq->dq_bhardlimit) { if ((dq->dq_flags & DQ_BLKS) == 0 && dq->dq_own == u.u_quota) { uprintf("\nDISC LIMIT REACHED (%s) - WRITE FAILED\n", ip->i_fs->fs_fsmnt); dq->dq_flags |= DQ_BLKS; } return (EDQUOT); } /* * User is over quota, but not over limit * or is over limit, but we have been told * there is nothing we can do. */ dq->dq_curblocks += change; return (0); } /* * Check the inode limit, applying corrective action. */ chkiq(dev, ip, uid, force) dev_t dev; uid_t uid; register struct inode *ip; int force; { register struct dquot *dq; register struct quota *q; if (ip == NULL) { /* allocation */ q = qfind(uid); if (q != NOQUOTA) dq = dqp(q, dev); else dq = discquota(uid, mount[getfsx(dev)].m_qinod); } else { /* free */ #ifdef pdp11 dq = ix_dquot[ip - inode]; #else dq = ip->i_dquot; #endif if (dq != NODQUOT) dq->dq_cnt++; } if (dq == NODQUOT) return (0); if (dq->dq_isoftlimit == 0) { dqrele(dq); return (0); } dq->dq_flags |= DQ_MOD; if (ip) { /* a free */ if (dq->dq_curinodes) dq->dq_curinodes--; dq->dq_flags &= ~DQ_INODS; dqrele(dq); return (0); } /* * The following shouldn't be necessary, as if u.u_uid == 0 * then dq == NODQUOT & we wouldn't get here at all, but * then again, its not going to harm anything ... */ if (u.u_uid == 0) /* su's musn't be stopped */ force = 1; if (!force && dq->dq_iwarn == 0) { if ((dq->dq_flags & DQ_INODS) == 0 && dq->dq_own == u.u_quota) { uprintf("\nOVER FILE QUOTA - NO MORE FILES (%s)\n", getfs(dq->dq_dev)->fs_fsmnt); dq->dq_flags |= DQ_INODS; } dqrele(dq); return (EDQUOT); } if (dq->dq_curinodes < dq->dq_isoftlimit) { if (++dq->dq_curinodes >= dq->dq_isoftlimit && dq->dq_own == u.u_quota) uprintf("\nWARNING - too many files (%s)\n", getfs(dq->dq_dev)->fs_fsmnt); dqrele(dq); return (0); } if (!force && dq->dq_ihardlimit && dq->dq_curinodes + 1 >= dq->dq_ihardlimit) { if ((dq->dq_flags & DQ_INODS) == 0 && dq->dq_own == u.u_quota) { uprintf("\nFILE LIMIT REACHED - CREATE FAILED (%s)\n", getfs(dq->dq_dev)->fs_fsmnt); dq->dq_flags |= DQ_INODS; } dqrele(dq); return (EDQUOT); } /* * Over quota but not at limit; * or over limit, but we aren't * allowed to stop it. */ dq->dq_curinodes++; dqrele(dq); return (0); } #endif