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

📄 xfs_qm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
			 */			xfs_qm_dqflock_pushbuf_wait(dqp);		}		/*		 * Let go of the mplist lock. We don't want to hold it		 * across a disk write.		 */		xfs_qm_mplist_unlock(mp);		error = xfs_qm_dqflush(dqp, flags);		xfs_dqunlock(dqp);		if (error)			return (error);		xfs_qm_mplist_lock(mp);		if (recl != XFS_QI_MPLRECLAIMS(mp)) {			xfs_qm_mplist_unlock(mp);			/* XXX restart limit */			goto again;		}	}	xfs_qm_mplist_unlock(mp);	/* return ! busy */	return (0);}/* * Release the group dquot pointers the user dquots may be * carrying around as a hint. mplist is locked on entry and exit. */STATIC voidxfs_qm_detach_gdquots(	xfs_mount_t	*mp){	xfs_dquot_t	*dqp, *gdqp;	int		nrecl; again:	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));	dqp = XFS_QI_MPLNEXT(mp);	while (dqp) {		xfs_dqlock(dqp);		if ((gdqp = dqp->q_gdquot)) {			xfs_dqlock(gdqp);			dqp->q_gdquot = NULL;		}		xfs_dqunlock(dqp);		if (gdqp) {			/*			 * Can't hold the mplist lock across a dqput.			 * XXXmust convert to marker based iterations here.			 */			nrecl = XFS_QI_MPLRECLAIMS(mp);			xfs_qm_mplist_unlock(mp);			xfs_qm_dqput(gdqp);			xfs_qm_mplist_lock(mp);			if (nrecl != XFS_QI_MPLRECLAIMS(mp))				goto again;		}		dqp = dqp->MPL_NEXT;	}}/* * Go through all the incore dquots of this file system and take them * off the mplist and hashlist, if the dquot type matches the dqtype * parameter. This is used when turning off quota accounting for * users and/or groups, as well as when the filesystem is unmounting. */STATIC intxfs_qm_dqpurge_int(	xfs_mount_t	*mp,	uint		flags) /* QUOTAOFF/UMOUNTING/UQUOTA/PQUOTA/GQUOTA */{	xfs_dquot_t	*dqp;	uint		dqtype;	int		nrecl;	xfs_dquot_t	*nextdqp;	int		nmisses;	if (mp->m_quotainfo == NULL)		return (0);	dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;	dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0;	dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;	xfs_qm_mplist_lock(mp);	/*	 * In the first pass through all incore dquots of this filesystem,	 * we release the group dquot pointers the user dquots may be	 * carrying around as a hint. We need to do this irrespective of	 * what's being turned off.	 */	xfs_qm_detach_gdquots(mp);      again:	nmisses = 0;	ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));	/*	 * Try to get rid of all of the unwanted dquots. The idea is to	 * get them off mplist and hashlist, but leave them on freelist.	 */	dqp = XFS_QI_MPLNEXT(mp);	while (dqp) {		/*		 * It's OK to look at the type without taking dqlock here.		 * We're holding the mplist lock here, and that's needed for		 * a dqreclaim.		 */		if ((dqp->dq_flags & dqtype) == 0) {			dqp = dqp->MPL_NEXT;			continue;		}		if (! xfs_qm_dqhashlock_nowait(dqp)) {			nrecl = XFS_QI_MPLRECLAIMS(mp);			xfs_qm_mplist_unlock(mp);			XFS_DQ_HASH_LOCK(dqp->q_hash);			xfs_qm_mplist_lock(mp);			/*			 * XXXTheoretically, we can get into a very long			 * ping pong game here.			 * No one can be adding dquots to the mplist at			 * this point, but somebody might be taking things off.			 */			if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {				XFS_DQ_HASH_UNLOCK(dqp->q_hash);				goto again;			}		}		/*		 * Take the dquot off the mplist and hashlist. It may remain on		 * freelist in INACTIVE state.		 */		nextdqp = dqp->MPL_NEXT;		nmisses += xfs_qm_dqpurge(dqp, flags);		dqp = nextdqp;	}	xfs_qm_mplist_unlock(mp);	return nmisses;}intxfs_qm_dqpurge_all(	xfs_mount_t	*mp,	uint		flags){	int		ndquots;	/*	 * Purge the dquot cache.	 * None of the dquots should really be busy at this point.	 */	if (mp->m_quotainfo) {		while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {			delay(ndquots * 10);		}	}	return 0;}STATIC intxfs_qm_dqattach_one(	xfs_inode_t	*ip,	xfs_dqid_t	id,	uint		type,	uint		doalloc,	uint		dolock,	xfs_dquot_t	*udqhint, /* hint */	xfs_dquot_t	**IO_idqpp){	xfs_dquot_t	*dqp;	int		error;	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));	error = 0;	/*	 * See if we already have it in the inode itself. IO_idqpp is	 * &i_udquot or &i_gdquot. This made the code look weird, but	 * made the logic a lot simpler.	 */	if ((dqp = *IO_idqpp)) {		if (dolock)			xfs_dqlock(dqp);		xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");		goto done;	}	/*	 * udqhint is the i_udquot field in inode, and is non-NULL only	 * when the type arg is group/project. Its purpose is to save a	 * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside	 * the user dquot.	 */	ASSERT(!udqhint || type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);	if (udqhint && !dolock)		xfs_dqlock(udqhint);	/*	 * No need to take dqlock to look at the id.	 * The ID can't change until it gets reclaimed, and it won't	 * be reclaimed as long as we have a ref from inode and we hold	 * the ilock.	 */	if (udqhint &&	    (dqp = udqhint->q_gdquot) &&	    (be32_to_cpu(dqp->q_core.d_id) == id)) {		ASSERT(XFS_DQ_IS_LOCKED(udqhint));		xfs_dqlock(dqp);		XFS_DQHOLD(dqp);		ASSERT(*IO_idqpp == NULL);		*IO_idqpp = dqp;		if (!dolock) {			xfs_dqunlock(dqp);			xfs_dqunlock(udqhint);		}		goto done;	}	/*	 * We can't hold a dquot lock when we call the dqget code.	 * We'll deadlock in no time, because of (not conforming to)	 * lock ordering - the inodelock comes before any dquot lock,	 * and we may drop and reacquire the ilock in xfs_qm_dqget().	 */	if (udqhint)		xfs_dqunlock(udqhint);	/*	 * Find the dquot from somewhere. This bumps the	 * reference count of dquot and returns it locked.	 * This can return ENOENT if dquot didn't exist on	 * disk and we didn't ask it to allocate;	 * ESRCH if quotas got turned off suddenly.	 */	if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,				 doalloc|XFS_QMOPT_DOWARN, &dqp))) {		if (udqhint && dolock)			xfs_dqlock(udqhint);		goto done;	}	xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");	/*	 * dqget may have dropped and re-acquired the ilock, but it guarantees	 * that the dquot returned is the one that should go in the inode.	 */	*IO_idqpp = dqp;	ASSERT(dqp);	ASSERT(XFS_DQ_IS_LOCKED(dqp));	if (! dolock) {		xfs_dqunlock(dqp);		goto done;	}	if (! udqhint)		goto done;	ASSERT(udqhint);	ASSERT(dolock);	ASSERT(XFS_DQ_IS_LOCKED(dqp));	if (! xfs_qm_dqlock_nowait(udqhint)) {		xfs_dqunlock(dqp);		xfs_dqlock(udqhint);		xfs_dqlock(dqp);	}      done:#ifdef QUOTADEBUG	if (udqhint) {		if (dolock)			ASSERT(XFS_DQ_IS_LOCKED(udqhint));	}	if (! error) {		if (dolock)			ASSERT(XFS_DQ_IS_LOCKED(dqp));	}#endif	return (error);}/* * Given a udquot and gdquot, attach a ptr to the group dquot in the * udquot as a hint for future lookups. The idea sounds simple, but the * execution isn't, because the udquot might have a group dquot attached * already and getting rid of that gets us into lock ordering contraints. * The process is complicated more by the fact that the dquots may or may not * be locked on entry. */STATIC voidxfs_qm_dqattach_grouphint(	xfs_dquot_t	*udq,	xfs_dquot_t	*gdq,	uint		locked){	xfs_dquot_t	*tmp;#ifdef QUOTADEBUG	if (locked) {		ASSERT(XFS_DQ_IS_LOCKED(udq));		ASSERT(XFS_DQ_IS_LOCKED(gdq));	}#endif	if (! locked)		xfs_dqlock(udq);	if ((tmp = udq->q_gdquot)) {		if (tmp == gdq) {			if (! locked)				xfs_dqunlock(udq);			return;		}		udq->q_gdquot = NULL;		/*		 * We can't keep any dqlocks when calling dqrele,		 * because the freelist lock comes before dqlocks.		 */		xfs_dqunlock(udq);		if (locked)			xfs_dqunlock(gdq);		/*		 * we took a hard reference once upon a time in dqget,		 * so give it back when the udquot no longer points at it		 * dqput() does the unlocking of the dquot.		 */		xfs_qm_dqrele(tmp);		xfs_dqlock(udq);		xfs_dqlock(gdq);	} else {		ASSERT(XFS_DQ_IS_LOCKED(udq));		if (! locked) {			xfs_dqlock(gdq);		}	}	ASSERT(XFS_DQ_IS_LOCKED(udq));	ASSERT(XFS_DQ_IS_LOCKED(gdq));	/*	 * Somebody could have attached a gdquot here,	 * when we dropped the uqlock. If so, just do nothing.	 */	if (udq->q_gdquot == NULL) {		XFS_DQHOLD(gdq);		udq->q_gdquot = gdq;	}	if (! locked) {		xfs_dqunlock(gdq);		xfs_dqunlock(udq);	}}/* * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON * into account. * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed. * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty * much made this code a complete mess, but it has been pretty useful. * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL. * Inode may get unlocked and relocked in here, and the caller must deal with * the consequences. */intxfs_qm_dqattach(	xfs_inode_t	*ip,	uint		flags){	xfs_mount_t	*mp = ip->i_mount;	uint		nquotas = 0;	int		error = 0;	if ((! XFS_IS_QUOTA_ON(mp)) ||	    (! XFS_NOT_DQATTACHED(mp, ip)) ||	    (ip->i_ino == mp->m_sb.sb_uquotino) ||	    (ip->i_ino == mp->m_sb.sb_gquotino))		return (0);	ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||	       XFS_ISLOCKED_INODE_EXCL(ip));	if (! (flags & XFS_QMOPT_ILOCKED))		xfs_ilock(ip, XFS_ILOCK_EXCL);	if (XFS_IS_UQUOTA_ON(mp)) {		error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,						flags & XFS_QMOPT_DQALLOC,						flags & XFS_QMOPT_DQLOCK,						NULL, &ip->i_udquot);		if (error)			goto done;		nquotas++;	}	ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));	if (XFS_IS_OQUOTA_ON(mp)) {		error = XFS_IS_GQUOTA_ON(mp) ?			xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,						flags & XFS_QMOPT_DQALLOC,						flags & XFS_QMOPT_DQLOCK,						ip->i_udquot, &ip->i_gdquot) :			xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ,						flags & XFS_QMOPT_DQALLOC,						flags & XFS_QMOPT_DQLOCK,						ip->i_udquot, &ip->i_gdquot);		/*		 * Don't worry about the udquot that we may have		 * attached above. It'll get detached, if not already.		 */		if (error)			goto done;		nquotas++;	}	/*	 * Attach this group quota to the user quota as a hint.	 * This WON'T, in general, result in a thrash.	 */	if (nquotas == 2) {		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));		ASSERT(ip->i_udquot);		ASSERT(ip->i_gdquot);		/*		 * We may or may not have the i_udquot locked at this point,		 * but this check is OK since we don't depend on the i_gdquot to		 * be accurate 100% all the time. It is just a hint, and this		 * will succeed in general.		 */		if (ip->i_udquot->q_gdquot == ip->i_gdquot)			goto done;		/*		 * Attach i_gdquot to the gdquot hint inside the i_udquot.		 */		xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,					 flags & XFS_QMOPT_DQLOCK);	}      done:#ifdef QUOTADEBUG	if (! error) {		if (ip->i_udquot) {			if (flags & XFS_QMOPT_DQLOCK)				ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));		}		if (ip->i_gdquot) {			if (flags & XFS_QMOPT_DQLOCK)				ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));		}		if (XFS_IS_UQUOTA_ON(mp))			ASSERT(ip->i_udquot);		if (XFS_IS_OQUOTA_ON(mp))			ASSERT(ip->i_gdquot);	}#endif	if (! (flags & XFS_QMOPT_ILOCKED))		xfs_iunlock(ip, XFS_ILOCK_EXCL);#ifdef QUOTADEBUG	else		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));#endif	return (error);}/* * Release dquots (and their references) if any. * The inode should be locked EXCL except when this's called by * xfs_ireclaim. */voidxfs_qm_dqdetach(	xfs_inode_t	*ip){	if (!(ip->i_udquot || ip->i_gdquot))		return;	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);	if (ip->i_udquot) {		xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);		xfs_qm_dqrele(ip->i_udquot);		ip->i_udquot = NULL;	}	if (ip->i_gdquot) {		xfs_dqtrace_entry_ino(ip->i_gdquot, "DQDETTACH", ip);		xfs_qm_dqrele(ip->i_gdquot);		ip->i_gdquot = NULL;	}}/* * This is called by VFS_SYNC and flags arg determines the caller, * and its motives, as done in xfs_sync. * * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31 * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25 * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA */intxfs_qm_sync(	xfs_mount_t	*mp,	short		flags){	int		recl, restarts;	xfs_dquot_t	*dqp;	uint		flush_flags;	boolean_t	nowait;	int		error;	restarts = 0;	/*	 * We won't block unless we are asked to.

⌨️ 快捷键说明

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