2.11BSD-UFS/quota_ufs.c
/*
* 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