Quota system cleanup.
1) Do not do quota accounting for the actual quota data files or for file system snapshot files ("system" files). This prevents a deadlock descibed in PR kern/30958 if the kernel ever has to grow the quota file. Snapshot files were already exempt from the quota checks, but this change generalized the check. 2) Fix a cast that caused extremely large uids/gids to incorrectly write the quota information to the data file at a truncated value for a uint_t32 id value. The incorrect cast caused quota files in this case to be around 4GB in size, with the correct cast they can now be 131GB in size. Also related to PR kern/30958. 3) Check for what appear to be negative UIDs/GIDs and not account for them. This prevents the quota files from becoming 131GB in size and causing quotacheck to run forever at bootup. This could also cause the kernel to try and expand the quota file, which might deadlock due to the issue in #1. kern/30958 and kern/38156 (and some much older closed PR's). 4) With the deadlock problems gone, the kernel can now expand the size of the quota database files if it needs to. 5) Pass in the i-node count change value to chkiq and chkiqchg as an int, like it used to be before the common routine was split up into 2 different routines to increase / decrease the i-node in-use count. Prevents an underflow on the i-node count. Related to PR kern/89247. 6) Prevent the block usage from growing slowly if a file system is full and the write was denied due to that fact. PR kern/89247. Some of these changes require an updated quotacheck to prevent the creation of huge (131GB) quota data files (item #3). #1/#4 probably fixes a lot of the random hangs when quotas are enabled, possibly some of the jail hangs.
This commit is contained in:
parent
f0cad96d23
commit
db9b81eabc
@ -188,6 +188,7 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp)
|
||||
*bnp = bno;
|
||||
return (0);
|
||||
}
|
||||
nospace:
|
||||
#ifdef QUOTA
|
||||
UFS_UNLOCK(ump);
|
||||
/*
|
||||
@ -196,7 +197,6 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp)
|
||||
(void) chkdq(ip, -btodb(size), cred, FORCE);
|
||||
UFS_LOCK(ump);
|
||||
#endif
|
||||
nospace:
|
||||
if (fs->fs_pendingblocks > 0 && reclaimed == 0) {
|
||||
reclaimed = 1;
|
||||
softdep_request_cleanup(fs, ITOV(ip));
|
||||
|
@ -281,6 +281,7 @@ ffs_snapshot(mp, snapfile)
|
||||
return (error);
|
||||
}
|
||||
vp = nd.ni_vp;
|
||||
vp->v_vflag |= VV_SYSTEM;
|
||||
ip = VTOI(vp);
|
||||
devvp = ip->i_devvp;
|
||||
/*
|
||||
@ -367,18 +368,6 @@ ffs_snapshot(mp, snapfile)
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
#ifdef QUOTA
|
||||
/*
|
||||
* Turn off disk quotas for snapshot file.
|
||||
*/
|
||||
(void) chkdq(ip, -DIP(ip, i_blocks), KERNCRED, FORCE);
|
||||
for (i = 0; i < MAXQUOTAS; i++) {
|
||||
if (ip->i_dquot[i] != NODQUOT) {
|
||||
dqrele(vp, ip->i_dquot[i]);
|
||||
ip->i_dquot[i] = NODQUOT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Change inode to snapshot type file.
|
||||
*/
|
||||
@ -682,7 +671,6 @@ ffs_snapshot(mp, snapfile)
|
||||
devvp->v_vflag |= VV_COPYONWRITE;
|
||||
VI_UNLOCK(devvp);
|
||||
ASSERT_VOP_LOCKED(vp, "ffs_snapshot vp");
|
||||
vp->v_vflag |= VV_SYSTEM;
|
||||
out1:
|
||||
KASSERT((sn != NULL && sbp != NULL && error == 0) ||
|
||||
(sn == NULL && sbp == NULL && error != 0),
|
||||
|
@ -174,7 +174,7 @@ struct ucred;
|
||||
struct vnode;
|
||||
|
||||
int chkdq(struct inode *, int64_t, struct ucred *, int);
|
||||
int chkiq(struct inode *, ino_t, struct ucred *, int);
|
||||
int chkiq(struct inode *, int, struct ucred *, int);
|
||||
void dqinit(void);
|
||||
void dqrele(struct vnode *, struct dquot *);
|
||||
void dquninit(void);
|
||||
|
@ -72,7 +72,7 @@ static MALLOC_DEFINE(M_DQUOT, "ufs_quota", "UFS quota entries");
|
||||
static char *quotatypes[] = INITQFNAMES;
|
||||
|
||||
static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int);
|
||||
static int chkiqchg(struct inode *, ino_t, struct ucred *, int);
|
||||
static int chkiqchg(struct inode *, int, struct ucred *, int);
|
||||
static int dqget(struct vnode *,
|
||||
u_long, struct ufsmount *, int, struct dquot **);
|
||||
static int dqsync(struct vnode *, struct dquot *);
|
||||
@ -99,13 +99,18 @@ getinoquota(ip)
|
||||
struct vnode *vp = ITOV(ip);
|
||||
int error;
|
||||
|
||||
#ifndef NO_FFS_SNAPSHOT
|
||||
/*
|
||||
* Disk quotas must be turned off for snapshot files.
|
||||
* Disk quotas must be turned off for system files. Currently
|
||||
* snapshot and quota files.
|
||||
*/
|
||||
if ((ip->i_flags & SF_SNAPSHOT) != 0)
|
||||
if ((vp->v_vflag & VV_SYSTEM) != 0)
|
||||
return (0);
|
||||
/*
|
||||
* XXX: Turn off quotas for files with a negative UID or GID.
|
||||
* This prevents the creation of 100GB+ quota files.
|
||||
*/
|
||||
if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
|
||||
return (0);
|
||||
#endif
|
||||
ump = VFSTOUFS(vp->v_mount);
|
||||
/*
|
||||
* Set up the user quota based on file uid.
|
||||
@ -140,8 +145,21 @@ chkdq(ip, change, cred, flags)
|
||||
{
|
||||
struct dquot *dq;
|
||||
ufs2_daddr_t ncurblocks;
|
||||
struct vnode *vp = ITOV(ip);
|
||||
int i, error;
|
||||
|
||||
/*
|
||||
* Disk quotas must be turned off for system files. Currently
|
||||
* snapshot and quota files.
|
||||
*/
|
||||
if ((vp->v_vflag & VV_SYSTEM) != 0)
|
||||
return (0);
|
||||
/*
|
||||
* XXX: Turn off quotas for files with a negative UID or GID.
|
||||
* This prevents the creation of 100GB+ quota files.
|
||||
*/
|
||||
if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
|
||||
return (0);
|
||||
#ifdef DIAGNOSTIC
|
||||
if ((flags & CHOWN) == 0)
|
||||
chkdquot(ip);
|
||||
@ -256,7 +274,7 @@ chkdqchg(ip, change, cred, type)
|
||||
int
|
||||
chkiq(ip, change, cred, flags)
|
||||
struct inode *ip;
|
||||
ino_t change;
|
||||
int change;
|
||||
struct ucred *cred;
|
||||
int flags;
|
||||
{
|
||||
@ -270,7 +288,6 @@ chkiq(ip, change, cred, flags)
|
||||
#endif
|
||||
if (change == 0)
|
||||
return (0);
|
||||
/* XXX: change is unsigned */
|
||||
if (change < 0) {
|
||||
for (i = 0; i < MAXQUOTAS; i++) {
|
||||
if ((dq = ip->i_dquot[i]) == NODQUOT)
|
||||
@ -281,7 +298,7 @@ chkiq(ip, change, cred, flags)
|
||||
}
|
||||
ncurinodes = dq->dq_curinodes + change;
|
||||
/* XXX: ncurinodes is unsigned */
|
||||
if (ncurinodes >= 0)
|
||||
if (dq->dq_curinodes != 0 && ncurinodes >= 0)
|
||||
dq->dq_curinodes = ncurinodes;
|
||||
else
|
||||
dq->dq_curinodes = 0;
|
||||
@ -325,7 +342,7 @@ chkiq(ip, change, cred, flags)
|
||||
static int
|
||||
chkiqchg(ip, change, cred, type)
|
||||
struct inode *ip;
|
||||
ino_t change;
|
||||
int change;
|
||||
struct ucred *cred;
|
||||
int type;
|
||||
{
|
||||
@ -384,15 +401,21 @@ chkdquot(ip)
|
||||
struct inode *ip;
|
||||
{
|
||||
struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount);
|
||||
struct vnode *vp = ITOV(ip);
|
||||
int i;
|
||||
|
||||
#ifndef NO_FFS_SNAPSHOT
|
||||
/*
|
||||
* Disk quotas must be turned off for snapshot files.
|
||||
* Disk quotas must be turned off for system files. Currently
|
||||
* these are snapshots and quota files.
|
||||
*/
|
||||
if ((ip->i_flags & SF_SNAPSHOT) != 0)
|
||||
if ((vp->v_vflag & VV_SYSTEM) != 0)
|
||||
return;
|
||||
#endif
|
||||
/*
|
||||
* XXX: Turn off quotas for files with a negative UID or GID.
|
||||
* This prevents the creation of 100GB+ quota files.
|
||||
*/
|
||||
if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
|
||||
return (0);
|
||||
for (i = 0; i < MAXQUOTAS; i++) {
|
||||
if (ump->um_quotas[i] == NULLVP ||
|
||||
(ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
|
||||
@ -929,7 +952,7 @@ dqget(vp, id, ump, type, dqp)
|
||||
aiov.iov_base = &dq->dq_dqb;
|
||||
aiov.iov_len = sizeof (struct dqblk);
|
||||
auio.uio_resid = sizeof (struct dqblk);
|
||||
auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
|
||||
auio.uio_offset = (off_t)id * sizeof (struct dqblk);
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_rw = UIO_READ;
|
||||
auio.uio_td = (struct thread *)0;
|
||||
@ -1044,7 +1067,7 @@ dqsync(vp, dq)
|
||||
aiov.iov_base = &dq->dq_dqb;
|
||||
aiov.iov_len = sizeof (struct dqblk);
|
||||
auio.uio_resid = sizeof (struct dqblk);
|
||||
auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
|
||||
auio.uio_offset = (off_t)dq->dq_id * sizeof (struct dqblk);
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_rw = UIO_WRITE;
|
||||
auio.uio_td = (struct thread *)0;
|
||||
|
Loading…
Reference in New Issue
Block a user