⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gfs_kernquota.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifndef lintstatic char *sccsid = "@(#)gfs_kernquota.c	4.2	ULTRIX	11/9/90";#endif/************************************************************************ *									* *			Copyright (c) 1986 by				* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//************************************************************************ * *			Modification History * *	prs 06 Apr 89 *	Added SMP quota. * *	koehler 11 Sep 86 *	changed namei interface * *	Stephen Reilly, 09-Sept-85 *	Modified to handle the new 4.3BSD namei code. * ***********************************************************************/#ifdef QUOTA/* * MELBOURNE QUOTAS * * Code pertaining to management of the in-core data structures. */#include "../h/param.h"#include "../h/systm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/proc.h"#include "../h/gnode.h"#include "../h/quota.h"#include "../h/mount.h"#include "../h/uio.h"#include "../h/kmalloc.h"/* * Quota cache - hash chain headers. */#define	NQHASH		32		/* a small prime */#if	(NQHASH&(NQHASH-1) == 0)#define	QHASH(uid)	((unsigned)(uid) & (NQHASH-1))#else#define	QHASH(uid)	((unsigned)(uid) % NQHASH)#endifstruct	qhash	{	struct	qhash	*qh_forw;	/* MUST be first */	struct	qhash	*qh_back;	/* MUST be second */};struct	qhash	qhash[NQHASH];/* * Quota free list. */struct	quota	*qfreelist, **qfreetail;typedef	struct quota *Qptr;#ifdef GFSDEBUGextern short GFS[];#endif/* * Dquot cache - hash chain headers. */#define	NDQHASH		64		/* a smallish prime */#if	(NDQHASH&(NDQHASH-1) == 0)#define	DQHASH(uid, dev) \	((unsigned)(((int)(dev) * 4) + (uid)) & (NDQHASH-1))#else#define	DQHASH(uid, dev) \	((unsigned)(((int)(dev) * 4) + (uid)) % NDQHASH)#endifstruct	dqhead	{	struct	dqhead	*dqh_forw;	/* MUST be first */	struct	dqhead	*dqh_back;	/* MUST be second */};struct	dqhead	dqhead[NDQHASH];/* * Dquot free list. */struct	dquot	*dqfreel, **dqback;typedef	struct dquot *DQptr;/* * Quota subsystem SMP sleep locks */struct lock_t lk_quota;struct lock_t lk_dquot;struct lock_t lk_quotalocks;struct lock_t lk_dquotlocks;extern struct lock_t lk_gnode;struct quota_active qactive[NMOUNT];/* * Initialize quota caches. */qtinit(){	register int i;	register struct quota *q = quota;	register struct qhash *qh = qhash;	register struct dquot *dq = dquot;	register struct dqhead *dh = dqhead;	lockinit(&lk_quotalocks, &lock_quotalocks_d);	lockinit(&lk_quota, &lock_quota_d);	lockinit(&lk_dquotlocks, &lock_dquotlocks_d);	lockinit(&lk_dquot, &lock_dquot_d);	/*	 * First the cache of structures assigned users.	 */	for (i = NQHASH; --i >= 0; qh++)		qh->qh_forw = qh->qh_back = qh;	qfreelist = q;	qfreetail = &q->q_freef;	q->q_freeb = &qfreelist;	q->q_forw = q;	q->q_back = q;	for (i = nquota; --i > 0; ) {		++q;		q->q_forw = q;		q->q_back = q;		*qfreetail = q;		q->q_freeb = qfreetail;		qfreetail = &q->q_freef;	}	q->q_freef = NOQUOTA;	/*	 * Next, the cache between the in-core structures	 * and the per-filesystem quota files on disk.	 */	for (i = NDQHASH; --i >= 0; dh++)		dh->dqh_forw = dh->dqh_back = dh;	dqfreel = dq;	dqback = &dq->dq_freef;	dq->dq_freeb = &dqfreel;	dq->dq_forw = dq;	dq->dq_back = dq;	for (i = ndquot; --i > 0; ) {		++dq;		dq->dq_forw = dq;		dq->dq_back = dq;		*dqback = dq;		dq->dq_freeb = dqback;		dqback = &dq->dq_freef;	}	dq->dq_freef = NODQUOT;	/*	 * Zero out quota system active counters and flags.	 */	for (i = 0; i < NMOUNT; i++) {		qactive[i].atv_flag = 0;		qactive[i].atv_cnt = 0;	}}/* * quota_test_lock returns true if the quota is locked.  If the quota * is already locked, we return false. This routine is called when * the lock request cannot sleep. */quota_test_lock(q)	register struct quota *q;{	if (q) {		smp_lock(&lk_quotalocks, LK_RETRY);		if (q->q_state & Q_LOCK) {			return(0);		}		q->q_state |= Q_LOCK;		smp_unlock(&lk_quotalocks);	}	return(1);}/* * dquot_test_lock returns true if the dquot is locked.  If the dquot * is already locked, we return false. This routine is called when * the lock request cannot sleep. */dquot_test_lock(dq)	register struct dquot *dq;{	if (dq) {		smp_lock(&lk_dquotlocks, LK_RETRY);		if (dq->dq_state & DQ_LOCK) {			return(0);		}		dq->dq_state |= DQ_LOCK;		smp_unlock(&lk_dquotlocks);	}	return(1);}/* * Find an incore quota structure for a particular uid, * or make one.  If lookuponly is non-zero, just the lookup is performed. * If nodq is non-zero, the dquot structures are left uninitialized. */struct quota *getquota(uid, lookuponly, nodq)	register int uid;	int lookuponly, nodq;{	register struct quota *q;	register struct qhash *qh;	register struct dquot **dqq;	register struct mount *mp;	register struct quota *qq;	struct gnode *rgp;	/*	 * Fast check to see if an existing structure	 * can be reused with just a reference count change.	 */	q = u.u_quota;	if (q != NOQUOTA && q->q_uid == uid) {		quota_lock(q);		goto quick;	}	/*	 * Search the quota chache for a hit.	 */top:	smp_lock(&lk_quota, LK_RETRY);	qh = &qhash[QHASH(uid)];	for (q = (Qptr)qh->qh_forw; q != (Qptr)qh; q = q->q_forw) {		if (!quota_test_lock(q)) {			smp_unlock(&lk_quota);			sleep_unlock((caddr_t)q, PINOD+1, &lk_quotalocks);			goto top;		}		if (q->q_uid == uid) {			if (q->q_cnt == 0) {				if (lookuponly) {					quota_unlock(q);					smp_unlock(&lk_quota);					return (NOQUOTA);				}				/*				 * Take it off the free list.				 */				if ((qq = q->q_freef) != NOQUOTA)					qq->q_freeb = q->q_freeb;				else					qfreetail = q->q_freeb;				*q->q_freeb = qq;				smp_unlock(&lk_quota);				/*				 * Recover any lost dquot structs.				 */				if (!nodq)				for (dqq = q->q_dq, mp = mount;				    dqq < &q->q_dq[NMOUNT]; dqq++, mp++) {					rgp = (struct gnode *)fref(mp, NULL);					if (*dqq == LOSTDQUOT && rgp) {						*dqq = discquota(uid,							      mp->m_qinod);						if (*dqq != NODQUOT) {							(*dqq)->dq_own = q;							dquot_unlock((*dqq));						}					}					if (rgp)						grele(rgp);				}			} else				smp_unlock(&lk_quota);  quick:			q->q_cnt++;			if (q->q_cnt == 1)				q->q_flags |= Q_NEW | nodq;			return (q);		} else			quota_unlock(q);	}	if (lookuponly) {		smp_unlock(&lk_quota);		return (NOQUOTA);	}	/*	 * Take the quota that is at the head of the free list	 * (the longest unused quota).	 */	q = qfreelist;	if (q == NOQUOTA) {		tablefull("quota");/*		printf("Login limit reached\n"); */		u.u_error = EUSERS;		q = quota;		/* the su's slot - we must have one */		quota_lock(q);		q->q_cnt++;		smp_unlock(&lk_quota);		return (q);	}	/*	 * There is one - it is free no longer.	 */	qq = q->q_freef;	if (qq != NOQUOTA)		qq->q_freeb = &qfreelist;	qfreelist = qq;	/*	 * Now we are about to change this from one user to another	 * Must take this off hash chain for old user immediately, in	 * case some other process claims it before we are done.	 * We must then put it on the hash chain for the new user,	 * to make sure that we don't make two quota structs for one uid.	 * (the quota struct will then be locked till we are done).	 */	remque(q);	quota_lock(q);	q->q_uid = uid;	q->q_flags = 0;	q->q_cnt++;			/* q->q_cnt = 1; */	insque(q, qh);	smp_unlock(&lk_quota);	/*	 * Next, before filling in info for the new owning user,	 * we must get rid of any dquot structs that we own.	 */	for (mp = mount, dqq = q->q_dq; mp < &mount[NMOUNT]; mp++, dqq++) {		rgp = (struct gnode *)fref(mp, NULL);		if (*dqq != NODQUOT && *dqq != LOSTDQUOT) {						dquot_lock((*dqq));			(*dqq)->dq_own = NOQUOTA;			putdq(mp, *dqq, 1);			dquot_unlock((*dqq));		}		if (!nodq && rgp) {			*dqq = discquota(uid, mp->m_qinod);			if (*dqq != NODQUOT) {				if ((*dqq)->dq_uid != uid)					panic("got bad quota uid");				(*dqq)->dq_own = q;				dquot_unlock((*dqq));			}		} else			*dqq = NODQUOT;		if (rgp)			grele(rgp);	}	q->q_flags = Q_NEW | nodq;	return (q);}/* * Delete a quota, wakeup anyone waiting. */delquota(q)	register struct quota *q;{	register struct dquot **dqq;	register struct mount *mp;	register struct gnode *rgp;#ifdef SMP_DEBUG	if ((q->q_state & Q_LOCK) == 0)		panic("delquota: Quota should be locked");#endif	if (q->q_cnt != 1) {		q->q_cnt--;		return;	}	/*	 * If we own dquot structs, sync them to disc, but don't release	 * them - we might be recalled from the LRU chain.	 * As we will sit on the free list while we are waiting for that,	 * if dquot structs run out, ours will be taken away.	 */	if ((q->q_flags & Q_NDQ) == 0) {		mp = mount;		for (dqq = q->q_dq; dqq < &q->q_dq[NMOUNT]; dqq++, mp++) {			rgp = (struct gnode *)fref(mp, NULL);			if (rgp) {				dquot_lock((*dqq));				putdq(mp, *dqq, 0);				dquot_unlock((*dqq));				grele(rgp);			}		}	}	smp_lock(&lk_quota, LK_RETRY);	q->q_cnt--;	if (qfreelist != NOQUOTA) {		*qfreetail = q;		q->q_freeb = qfreetail;	} else {		qfreelist = q;		q->q_freeb = &qfreelist;	}	q->q_freef = NOQUOTA;	qfreetail = &q->q_freef;	q->q_flags = 0;	smp_unlock(&lk_quota); }/* * Obtain the user's on-disk quota limit * from the file specified. */struct dquot *discquota(uid, gp)	register struct gnode *gp;{	register struct dquot *dq;	register struct dqhead *dh;	register struct dquot *dp;	register int fail;#ifdef GFSDEBUG	if(GFS[8])		cprintf ("discquota: uid %d, gp 0x%x\n", uid, gp);#endif	if (gp == NULL)		return (NODQUOT);#ifdef SMP_DEBUG	if (gp->g_count <= 0) {		printf("discquota: gp 0x%x count %d \n", gp, gp->g_count);		panic("discquota: gp needs to have a non zero ref count");	}	if (smp_owner(&lk_quota) || smp_owner(&lk_dquot))		panic("discquota: cannot hold table locks");#endif	dq = dqalloc(uid, gp->g_dev);	if (dq == NODQUOT)		return (dq);	if (dq->dq_flags & DQ_HASH) {		dq->dq_flags &= ~DQ_HASH;		/*		 * We do this test after the reclaim so that		 * the dquot will be moved to the end of the free		 * list - frequently accessed ones ought to hang around.		 */		if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0) {			dqrele(dq);			dquot_unlock(dq);			return (NODQUOT);		}		return(dq);	}	/*         * Not in cache, initialize dq_dqb         * by reading the entry in the quotas file for uid.         */	gfs_lock(gp);	fail = rdwri(UIO_READ, gp, (caddr_t)&dq->dq_dqb, sizeof (struct dqblk),	    uid * sizeof (struct dqblk), 1, (int *)0);	gfs_unlock(gp);	/*	 * I/O error in reading quota file, release	 * quota structure and reflect problem to caller.	 */	if (fail) {		smp_lock(&lk_dquot, LK_RETRY);		remque(dq);		dq->dq_forw = dq;	/* on a private, unfindable hash list */		dq->dq_back = dq;		/* dqrele() (just below) will put dquot back on free list */		smp_unlock(&lk_dquot);	}	/* no quota exists */	if (fail || dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0) {		dqrele(dq);		dquot_unlock(dq);		return (NODQUOT);	}	return (dq);}/*

⌨️ 快捷键说明

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