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

📄 xfs_qm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;	     ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&	      nreclaimed < howmany); ) {		xfs_dqlock(dqp);		/*		 * We are racing with dqlookup here. Naturally we don't		 * want to reclaim a dquot that lookup wants.		 */		if (dqp->dq_flags & XFS_DQ_WANT) {			xfs_dqunlock(dqp);			xfs_qm_freelist_unlock(xfs_Gqm);			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)				return (nreclaimed);			XQM_STATS_INC(xqmstats.xs_qm_dqwants);			goto tryagain;		}		/*		 * If the dquot is inactive, we are assured that it is		 * not on the mplist or the hashlist, and that makes our		 * life easier.		 */		if (dqp->dq_flags & XFS_DQ_INACTIVE) {			ASSERT(dqp->q_mount == NULL);			ASSERT(! XFS_DQ_IS_DIRTY(dqp));			ASSERT(dqp->HL_PREVP == NULL);			ASSERT(dqp->MPL_PREVP == NULL);			XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);			nextdqp = dqp->dq_flnext;			goto off_freelist;		}		ASSERT(dqp->MPL_PREVP);		/*		 * Try to grab the flush lock. If this dquot is in the process of		 * getting flushed to disk, we don't want to reclaim it.		 */		if (! xfs_qm_dqflock_nowait(dqp)) {			xfs_dqunlock(dqp);			dqp = dqp->dq_flnext;			continue;		}		/*		 * We have the flush lock so we know that this is not in the		 * process of being flushed. So, if this is dirty, flush it		 * DELWRI so that we don't get a freelist infested with		 * dirty dquots.		 */		if (XFS_DQ_IS_DIRTY(dqp)) {			xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY");			/*			 * We flush it delayed write, so don't bother			 * releasing the mplock.			 */			(void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);			xfs_dqunlock(dqp); /* dqflush unlocks dqflock */			dqp = dqp->dq_flnext;			continue;		}		/*		 * We're trying to get the hashlock out of order. This races		 * with dqlookup; so, we giveup and goto the next dquot if		 * we couldn't get the hashlock. This way, we won't starve		 * a dqlookup process that holds the hashlock that is		 * waiting for the freelist lock.		 */		if (! xfs_qm_dqhashlock_nowait(dqp)) {			xfs_dqfunlock(dqp);			xfs_dqunlock(dqp);			dqp = dqp->dq_flnext;			continue;		}		/*		 * This races with dquot allocation code as well as dqflush_all		 * and reclaim code. So, if we failed to grab the mplist lock,		 * giveup everything and start over.		 */		hash = dqp->q_hash;		ASSERT(hash);		if (! xfs_qm_mplist_nowait(dqp->q_mount)) {			/* XXX put a sentinel so that we can come back here */			xfs_dqfunlock(dqp);			xfs_dqunlock(dqp);			XFS_DQ_HASH_UNLOCK(hash);			xfs_qm_freelist_unlock(xfs_Gqm);			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)				return (nreclaimed);			goto tryagain;		}		xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");#ifdef QUOTADEBUG		cmn_err(CE_DEBUG, "Shake 0x%p, ID 0x%x\n",			dqp, be32_to_cpu(dqp->q_core.d_id));#endif		ASSERT(dqp->q_nrefs == 0);		nextdqp = dqp->dq_flnext;		XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);		XQM_HASHLIST_REMOVE(hash, dqp);		xfs_dqfunlock(dqp);		xfs_qm_mplist_unlock(dqp->q_mount);		XFS_DQ_HASH_UNLOCK(hash); off_freelist:		XQM_FREELIST_REMOVE(dqp);		xfs_dqunlock(dqp);		nreclaimed++;		XQM_STATS_INC(xqmstats.xs_qm_dqshake_reclaims);		xfs_qm_dqdestroy(dqp);		dqp = nextdqp;	}	xfs_qm_freelist_unlock(xfs_Gqm);	return (nreclaimed);}/* * The kmem_shake interface is invoked when memory is running low. *//* ARGSUSED */STATIC intxfs_qm_shake(int nr_to_scan, gfp_t gfp_mask){	int	ndqused, nfree, n;	if (!kmem_shake_allow(gfp_mask))		return (0);	if (!xfs_Gqm)		return (0);	nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */	/* incore dquots in all f/s's */	ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;	ASSERT(ndqused >= 0);	if (nfree <= ndqused && nfree < ndquot)		return (0);	ndqused *= xfs_Gqm->qm_dqfree_ratio;	/* target # of free dquots */	n = nfree - ndqused - ndquot;		/* # over target */	return xfs_qm_shake_freelist(MAX(nfree, n));}/* * Just pop the least recently used dquot off the freelist and * recycle it. The returned dquot is locked. */STATIC xfs_dquot_t *xfs_qm_dqreclaim_one(void){	xfs_dquot_t	*dqpout;	xfs_dquot_t	*dqp;	int		restarts;	int		nflushes;	restarts = 0;	dqpout = NULL;	nflushes = 0;	/* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */ startagain:	xfs_qm_freelist_lock(xfs_Gqm);	FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {		xfs_dqlock(dqp);		/*		 * We are racing with dqlookup here. Naturally we don't		 * want to reclaim a dquot that lookup wants. We release the		 * freelist lock and start over, so that lookup will grab		 * both the dquot and the freelistlock.		 */		if (dqp->dq_flags & XFS_DQ_WANT) {			ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));			xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT");			xfs_dqunlock(dqp);			xfs_qm_freelist_unlock(xfs_Gqm);			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)				return (NULL);			XQM_STATS_INC(xqmstats.xs_qm_dqwants);			goto startagain;		}		/*		 * If the dquot is inactive, we are assured that it is		 * not on the mplist or the hashlist, and that makes our		 * life easier.		 */		if (dqp->dq_flags & XFS_DQ_INACTIVE) {			ASSERT(dqp->q_mount == NULL);			ASSERT(! XFS_DQ_IS_DIRTY(dqp));			ASSERT(dqp->HL_PREVP == NULL);			ASSERT(dqp->MPL_PREVP == NULL);			XQM_FREELIST_REMOVE(dqp);			xfs_dqunlock(dqp);			dqpout = dqp;			XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);			break;		}		ASSERT(dqp->q_hash);		ASSERT(dqp->MPL_PREVP);		/*		 * Try to grab the flush lock. If this dquot is in the process of		 * getting flushed to disk, we don't want to reclaim it.		 */		if (! xfs_qm_dqflock_nowait(dqp)) {			xfs_dqunlock(dqp);			continue;		}		/*		 * We have the flush lock so we know that this is not in the		 * process of being flushed. So, if this is dirty, flush it		 * DELWRI so that we don't get a freelist infested with		 * dirty dquots.		 */		if (XFS_DQ_IS_DIRTY(dqp)) {			xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY");			/*			 * We flush it delayed write, so don't bother			 * releasing the freelist lock.			 */			(void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);			xfs_dqunlock(dqp); /* dqflush unlocks dqflock */			continue;		}		if (! xfs_qm_mplist_nowait(dqp->q_mount)) {			xfs_dqfunlock(dqp);			xfs_dqunlock(dqp);			continue;		}		if (! xfs_qm_dqhashlock_nowait(dqp))			goto mplistunlock;		ASSERT(dqp->q_nrefs == 0);		xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING");		XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);		XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);		XQM_FREELIST_REMOVE(dqp);		dqpout = dqp;		XFS_DQ_HASH_UNLOCK(dqp->q_hash); mplistunlock:		xfs_qm_mplist_unlock(dqp->q_mount);		xfs_dqfunlock(dqp);		xfs_dqunlock(dqp);		if (dqpout)			break;	}	xfs_qm_freelist_unlock(xfs_Gqm);	return (dqpout);}/*------------------------------------------------------------------*//* * Return a new incore dquot. Depending on the number of * dquots in the system, we either allocate a new one on the kernel heap, * or reclaim a free one. * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed * to reclaim an existing one from the freelist. */boolean_txfs_qm_dqalloc_incore(	xfs_dquot_t **O_dqpp){	xfs_dquot_t	*dqp;	/*	 * Check against high water mark to see if we want to pop	 * a nincompoop dquot off the freelist.	 */	if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {		/*		 * Try to recycle a dquot from the freelist.		 */		if ((dqp = xfs_qm_dqreclaim_one())) {			XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);			/*			 * Just zero the core here. The rest will get			 * reinitialized by caller. XXX we shouldn't even			 * do this zero ...			 */			memset(&dqp->q_core, 0, sizeof(dqp->q_core));			*O_dqpp = dqp;			return (B_FALSE);		}		XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);	}	/*	 * Allocate a brand new dquot on the kernel heap and return it	 * to the caller to initialize.	 */	ASSERT(xfs_Gqm->qm_dqzone != NULL);	*O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);	atomic_inc(&xfs_Gqm->qm_totaldquots);	return (B_TRUE);}/* * Start a transaction and write the incore superblock changes to * disk. flags parameter indicates which fields have changed. */intxfs_qm_write_sb_changes(	xfs_mount_t	*mp,	__int64_t	flags){	xfs_trans_t	*tp;	int		error;#ifdef QUOTADEBUG	cmn_err(CE_NOTE, "Writing superblock quota changes :%s", mp->m_fsname);#endif	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);	if ((error = xfs_trans_reserve(tp, 0,				      mp->m_sb.sb_sectsize + 128, 0,				      0,				      XFS_DEFAULT_LOG_COUNT))) {		xfs_trans_cancel(tp, 0);		return (error);	}	xfs_mod_sb(tp, flags);	(void) xfs_trans_commit(tp, 0, NULL);	return (0);}/* --------------- utility functions for vnodeops ---------------- *//* * Given an inode, a uid and gid (from cred_t) make sure that we have * allocated relevant dquot(s) on disk, and that we won't exceed inode * quotas by creating this file. * This also attaches dquot(s) to the given inode after locking it, * and returns the dquots corresponding to the uid and/or gid. * * in	: inode (unlocked) * out	: udquot, gdquot with references taken and unlocked */intxfs_qm_vop_dqalloc(	xfs_mount_t	*mp,	xfs_inode_t	*ip,	uid_t		uid,	gid_t		gid,	prid_t		prid,	uint		flags,	xfs_dquot_t	**O_udqpp,	xfs_dquot_t	**O_gdqpp){	int		error;	xfs_dquot_t	*uq, *gq;	uint		lockflags;	if (!XFS_IS_QUOTA_ON(mp))		return 0;	lockflags = XFS_ILOCK_EXCL;	xfs_ilock(ip, lockflags);	if ((flags & XFS_QMOPT_INHERIT) &&	    XFS_INHERIT_GID(ip, XFS_MTOVFS(mp)))		gid = ip->i_d.di_gid;	/*	 * Attach the dquot(s) to this inode, doing a dquot allocation	 * if necessary. The dquot(s) will not be locked.	 */	if (XFS_NOT_DQATTACHED(mp, ip)) {		if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |					    XFS_QMOPT_ILOCKED))) {			xfs_iunlock(ip, lockflags);			return (error);		}	}	uq = gq = NULL;	if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) {		if (ip->i_d.di_uid != uid) {			/*			 * What we need is the dquot that has this uid, and			 * if we send the inode to dqget, the uid of the inode			 * takes priority over what's sent in the uid argument.			 * We must unlock inode here before calling dqget if			 * we're not sending the inode, because otherwise			 * we'll deadlock by doing trans_reserve while			 * holding ilock.			 */			xfs_iunlock(ip, lockflags);			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,						 XFS_DQ_USER,						 XFS_QMOPT_DQALLOC |						 XFS_QMOPT_DOWARN,						 &uq))) {				ASSERT(error != ENOENT);				return (error);			}			/*			 * Get the ilock in the right order.			 */			xfs_dqunlock(uq);			lockflags = XFS_ILOCK_SHARED;			xfs_ilock(ip, lockflags);		} else {			/*			 * Take an extra reference, because we'll return			 * this to caller			 */			ASSERT(ip->i_udquot);			uq = ip->i_udquot;			xfs_dqlock(uq);			XFS_DQHOLD(uq);			xfs_dqunlock(uq);		}	}	if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {		if (ip->i_d.di_gid != gid) {			xfs_iunlock(ip, lockflags);			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,						 XFS_DQ_GROUP,						 XFS_QMOPT_DQALLOC |						 XFS_QMOPT_DOWARN,						 &gq))) {				if (uq)					xfs_qm_dqrele(uq);				ASSERT(error != ENOENT);				return (error);			}			xfs_dqunlock(gq);			lockflags = XFS_ILOCK_SHARED;			xfs_ilock(ip, lockflags);		} else {			ASSERT(ip->i_gdquot);			gq = ip->i_gdquot;			xfs_dqlock(gq);			XFS_DQHOLD(gq);			xfs_dqunlock(gq);		}	} else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {		if (ip->i_d.di_projid != prid) {			xfs_iunlock(ip, lockflags);			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,						 XFS_DQ_PROJ,						 XFS_QMOPT_DQALLOC |						 XFS_QMOPT_DOWARN,						 &gq))) {				if (uq)					xfs_qm_dqrele(uq);				ASSERT(error != ENOENT);				return (error);			}			xfs_dqunlock(gq);			lockflags = XFS_ILOCK_SHARED;			xfs_ilock(ip, lockflags);		} else {			ASSERT(ip->i_gdquot);			gq = ip->i_gdquot;			xfs_dqlock(gq);			XFS_DQHOLD(gq);			xfs_dqunlock(gq);		}	}	if (uq)		xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);	xfs_iunlock(ip, lockflags);	if (O_udqpp)		*O_udqpp = uq;	else if (uq)		xfs_qm_dqrele(uq);	if (O_gdqpp)		*O_gdqpp = gq;	else if (gq)		xfs_qm_dqrele(gq);	return (0);}/* * Actually transfer ownership, and do dquot modifications. * These were already reserved. */xfs_dquot_t *xfs_qm_vop_chown(	xfs_trans_t	*tp,	xfs_inode_t	*ip,	xfs_dquot_t	**IO_olddq,	xfs_dquot_t	*newdq){	xfs_dquot_t	*prevdq;	uint		bfield = XFS_IS_REALTIME_INODE(ip) ?				 XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));	/* old dquot */	prevdq = *IO_olddq;	ASSERT(prevdq);	ASSERT(prevdq != newdq);	xfs_trans_mod_dquot(tp, prevdq, bfield, -(ip->i_d.di_nblocks));	xfs_trans_mod_dquot(tp,

⌨️ 快捷键说明

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