ufs_quota.c

来自「早期freebsd实现」· C语言 代码 · 共 939 行 · 第 1/2 页

C
939
字号
	dqflush(qvp);	qvp->v_flag &= ~VSYSTEM;	error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);	ump->um_quotas[type] = NULLVP;	crfree(ump->um_cred[type]);	ump->um_cred[type] = NOCRED;	ump->um_qflags[type] &= ~QTF_CLOSING;	for (type = 0; type < MAXQUOTAS; type++)		if (ump->um_quotas[type] != NULLVP)			break;	if (type == MAXQUOTAS)		mp->mnt_flag &= ~MNT_QUOTA;	return (error);}/* * Q_GETQUOTA - return current values in a dqblk structure. */intgetquota(mp, id, type, addr)	struct mount *mp;	u_long id;	int type;	caddr_t addr;{	struct dquot *dq;	int error;	if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq))		return (error);	error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));	dqrele(NULLVP, dq);	return (error);}/* * Q_SETQUOTA - assign an entire dqblk structure. */intsetquota(mp, id, type, addr)	struct mount *mp;	u_long id;	int type;	caddr_t addr;{	register struct dquot *dq;	struct dquot *ndq;	struct ufsmount *ump = VFSTOUFS(mp);	struct dqblk newlim;	int error;	if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))		return (error);	if (error = dqget(NULLVP, id, ump, type, &ndq))		return (error);	dq = ndq;	while (dq->dq_flags & DQ_LOCK) {		dq->dq_flags |= DQ_WANT;		sleep((caddr_t)dq, PINOD+1);	}	/*	 * Copy all but the current values.	 * Reset time limit if previously had no soft limit or were	 * under it, but now have a soft limit and are over it.	 */	newlim.dqb_curblocks = dq->dq_curblocks;	newlim.dqb_curinodes = dq->dq_curinodes;	if (dq->dq_id != 0) {		newlim.dqb_btime = dq->dq_btime;		newlim.dqb_itime = dq->dq_itime;	}	if (newlim.dqb_bsoftlimit &&	    dq->dq_curblocks >= newlim.dqb_bsoftlimit &&	    (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))		newlim.dqb_btime = time.tv_sec + ump->um_btime[type];	if (newlim.dqb_isoftlimit &&	    dq->dq_curinodes >= newlim.dqb_isoftlimit &&	    (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))		newlim.dqb_itime = time.tv_sec + ump->um_itime[type];	dq->dq_dqb = newlim;	if (dq->dq_curblocks < dq->dq_bsoftlimit)		dq->dq_flags &= ~DQ_BLKS;	if (dq->dq_curinodes < dq->dq_isoftlimit)		dq->dq_flags &= ~DQ_INODS;	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)		dq->dq_flags |= DQ_FAKE;	else		dq->dq_flags &= ~DQ_FAKE;	dq->dq_flags |= DQ_MOD;	dqrele(NULLVP, dq);	return (0);}/* * Q_SETUSE - set current inode and block usage. */intsetuse(mp, id, type, addr)	struct mount *mp;	u_long id;	int type;	caddr_t addr;{	register struct dquot *dq;	struct ufsmount *ump = VFSTOUFS(mp);	struct dquot *ndq;	struct dqblk usage;	int error;	if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))		return (error);	if (error = dqget(NULLVP, id, ump, type, &ndq))		return (error);	dq = ndq;	while (dq->dq_flags & DQ_LOCK) {		dq->dq_flags |= DQ_WANT;		sleep((caddr_t)dq, PINOD+1);	}	/*	 * Reset time limit if have a soft limit and were	 * previously under it, but are now over it.	 */	if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&	    usage.dqb_curblocks >= dq->dq_bsoftlimit)		dq->dq_btime = time.tv_sec + ump->um_btime[type];	if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&	    usage.dqb_curinodes >= dq->dq_isoftlimit)		dq->dq_itime = time.tv_sec + ump->um_itime[type];	dq->dq_curblocks = usage.dqb_curblocks;	dq->dq_curinodes = usage.dqb_curinodes;	if (dq->dq_curblocks < dq->dq_bsoftlimit)		dq->dq_flags &= ~DQ_BLKS;	if (dq->dq_curinodes < dq->dq_isoftlimit)		dq->dq_flags &= ~DQ_INODS;	dq->dq_flags |= DQ_MOD;	dqrele(NULLVP, dq);	return (0);}/* * Q_SYNC - sync quota files to disk. */intqsync(mp)	struct mount *mp;{	struct ufsmount *ump = VFSTOUFS(mp);	register struct vnode *vp, *nextvp;	register struct dquot *dq;	register int i;	/*	 * Check if the mount point has any quotas.	 * If not, simply return.	 */	if ((mp->mnt_flag & MNT_MPBUSY) == 0)		panic("qsync: not busy");	for (i = 0; i < MAXQUOTAS; i++)		if (ump->um_quotas[i] != NULLVP)			break;	if (i == MAXQUOTAS)		return (0);	/*	 * Search vnodes associated with this mount point,	 * synchronizing any modified dquot structures.	 */again:	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {		nextvp = vp->v_mntvnodes.le_next;		if (VOP_ISLOCKED(vp))			continue;		if (vget(vp, 1))			goto again;		for (i = 0; i < MAXQUOTAS; i++) {			dq = VTOI(vp)->i_dquot[i];			if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))				dqsync(vp, dq);		}		vput(vp);		if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp)			goto again;	}	return (0);}/* * Code pertaining to management of the in-core dquot data structures. */struct dquot **dqhashtbl;u_long dqhash;/* * Dquot free list. */#define	DQUOTINC	5	/* minimum free dquots desired */struct dquot *dqfreel, **dqback = &dqfreel;long numdquot, desireddquot = DQUOTINC;/* * Initialize the quota system. */voiddqinit(){	dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash);}/* * Obtain a dquot structure for the specified identifier and quota file * reading the information from the file if necessary. */intdqget(vp, id, ump, type, dqp)	struct vnode *vp;	u_long id;	register struct ufsmount *ump;	register int type;	struct dquot **dqp;{	register struct dquot *dq, *dp, **dpp;	register struct vnode *dqvp;	struct iovec aiov;	struct uio auio;	int error;	dqvp = ump->um_quotas[type];	if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {		*dqp = NODQUOT;		return (EINVAL);	}	/*	 * Check the cache first.	 */	dpp = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash];	for (dq = *dpp; dq; dq = dq->dq_forw) {		if (dq->dq_id != id ||		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)			continue;		/*		 * Cache hit with no references.  Take		 * the structure off the free list.		 */		if (dq->dq_cnt == 0) {			if ((dp = dq->dq_freef) != NODQUOT)				dp->dq_freeb = dq->dq_freeb;			else				dqback = dq->dq_freeb;			*dq->dq_freeb = dp;		}		DQREF(dq);		*dqp = dq;		return (0);	}	/*	 * Not in cache, allocate a new one.	 */	if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes)		desireddquot += DQUOTINC;	if (numdquot < desireddquot) {		dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK);		bzero((char *)dq, sizeof *dq);		numdquot++;	} else {		if ((dq = dqfreel) == NULL) {			tablefull("dquot");			*dqp = NODQUOT;			return (EUSERS);		}		if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))			panic("free dquot isn't");		if ((dp = dq->dq_freef) != NODQUOT)			dp->dq_freeb = &dqfreel;		else			dqback = &dqfreel;		dqfreel = dp;		dq->dq_freef = NULL;		dq->dq_freeb = NULL;		if (dp = dq->dq_forw)			dp->dq_back = dq->dq_back;		*dq->dq_back = dp;	}	/*	 * Initialize the contents of the dquot structure.	 */	if (vp != dqvp)		VOP_LOCK(dqvp);	if (dp = *dpp)		dp->dq_back = &dq->dq_forw;	dq->dq_forw = dp;	dq->dq_back = dpp;	*dpp = dq;	DQREF(dq);	dq->dq_flags = DQ_LOCK;	dq->dq_id = id;	dq->dq_ump = ump;	dq->dq_type = type;	auio.uio_iov = &aiov;	auio.uio_iovcnt = 1;	aiov.iov_base = (caddr_t)&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_segflg = UIO_SYSSPACE;	auio.uio_rw = UIO_READ;	auio.uio_procp = (struct proc *)0;	error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);	if (auio.uio_resid == sizeof(struct dqblk) && error == 0)		bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk));	if (vp != dqvp)		VOP_UNLOCK(dqvp);	if (dq->dq_flags & DQ_WANT)		wakeup((caddr_t)dq);	dq->dq_flags = 0;	/*	 * I/O error in reading quota file, release	 * quota structure and reflect problem to caller.	 */	if (error) {		if (dp = dq->dq_forw)			dp->dq_back = dq->dq_back;		*dq->dq_back = dp;		dq->dq_forw = NULL;		dq->dq_back = NULL;		dqrele(vp, dq);		*dqp = NODQUOT;		return (error);	}	/*	 * Check for no limit to enforce.	 * Initialize time values if necessary.	 */	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)		dq->dq_flags |= DQ_FAKE;	if (dq->dq_id != 0) {		if (dq->dq_btime == 0)			dq->dq_btime = time.tv_sec + ump->um_btime[type];		if (dq->dq_itime == 0)			dq->dq_itime = time.tv_sec + ump->um_itime[type];	}	*dqp = dq;	return (0);}/* * Obtain a reference to a dquot. */voiddqref(dq)	struct dquot *dq;{	dq->dq_cnt++;}/* * Release a reference to a dquot. */voiddqrele(vp, dq)	struct vnode *vp;	register struct dquot *dq;{	if (dq == NODQUOT)		return;	if (dq->dq_cnt > 1) {		dq->dq_cnt--;		return;	}	if (dq->dq_flags & DQ_MOD)		(void) dqsync(vp, dq);	if (--dq->dq_cnt > 0)		return;	if (dqfreel != NODQUOT) {		*dqback = dq;		dq->dq_freeb = dqback;	} else {		dqfreel = dq;		dq->dq_freeb = &dqfreel;	}	dq->dq_freef = NODQUOT;	dqback = &dq->dq_freef;}/* * Update the disk quota in the quota file. */intdqsync(vp, dq)	struct vnode *vp;	register struct dquot *dq;{	struct vnode *dqvp;	struct iovec aiov;	struct uio auio;	int error;	if (dq == NODQUOT)		panic("dqsync: dquot");	if ((dq->dq_flags & DQ_MOD) == 0)		return (0);	if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)		panic("dqsync: file");	if (vp != dqvp)		VOP_LOCK(dqvp);	while (dq->dq_flags & DQ_LOCK) {		dq->dq_flags |= DQ_WANT;		sleep((caddr_t)dq, PINOD+2);		if ((dq->dq_flags & DQ_MOD) == 0) {			if (vp != dqvp)				VOP_UNLOCK(dqvp);			return (0);		}	}	dq->dq_flags |= DQ_LOCK;	auio.uio_iov = &aiov;	auio.uio_iovcnt = 1;	aiov.iov_base = (caddr_t)&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_segflg = UIO_SYSSPACE;	auio.uio_rw = UIO_WRITE;	auio.uio_procp = (struct proc *)0;	error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);	if (auio.uio_resid && error == 0)		error = EIO;	if (dq->dq_flags & DQ_WANT)		wakeup((caddr_t)dq);	dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);	if (vp != dqvp)		VOP_UNLOCK(dqvp);	return (error);}/* * Flush all entries from the cache for a particular vnode. */voiddqflush(vp)	register struct vnode *vp;{	register struct dquot *dq, *dp, **dpp, *nextdq;	/*	 * Move all dquot's that used to refer to this quota	 * file off their hash chains (they will eventually	 * fall off the head of the free list and be re-used).	 */	for (dpp = &dqhashtbl[dqhash]; dpp >= dqhashtbl; dpp--) {		for (dq = *dpp; dq; dq = nextdq) {			nextdq = dq->dq_forw;			if (dq->dq_ump->um_quotas[dq->dq_type] != vp)				continue;			if (dq->dq_cnt)				panic("dqflush: stray dquot");			if (dp = dq->dq_forw)				dp->dq_back = dq->dq_back;			*dq->dq_back = dp;			dq->dq_forw = NULL;			dq->dq_back = NULL;			dq->dq_ump = (struct ufsmount *)0;		}	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?