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

📄 xfs_qm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_clnt.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_alloc.h"#include "xfs_dmapi.h"#include "xfs_quota.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_itable.h"#include "xfs_rtalloc.h"#include "xfs_error.h"#include "xfs_bmap.h"#include "xfs_rw.h"#include "xfs_acl.h"#include "xfs_cap.h"#include "xfs_mac.h"#include "xfs_attr.h"#include "xfs_buf_item.h"#include "xfs_trans_space.h"#include "xfs_utils.h"#include "xfs_qm.h"/* * The global quota manager. There is only one of these for the entire * system, _not_ one per file system. XQM keeps track of the overall * quota functionality, including maintaining the freelist and hash * tables of dquots. */mutex_t		xfs_Gqm_lock;struct xfs_qm	*xfs_Gqm;uint		ndquot;kmem_zone_t	*qm_dqzone;kmem_zone_t	*qm_dqtrxzone;STATIC kmem_shaker_t	xfs_qm_shaker;STATIC void	xfs_qm_list_init(xfs_dqlist_t *, char *, int);STATIC void	xfs_qm_list_destroy(xfs_dqlist_t *);STATIC void	xfs_qm_freelist_init(xfs_frlist_t *);STATIC void	xfs_qm_freelist_destroy(xfs_frlist_t *);STATIC int	xfs_qm_mplist_nowait(xfs_mount_t *);STATIC int	xfs_qm_dqhashlock_nowait(xfs_dquot_t *);STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);STATIC int	xfs_qm_init_quotainfo(xfs_mount_t *);STATIC int	xfs_qm_shake(int, gfp_t);#ifdef DEBUGextern mutex_t	qcheck_lock;#endif#ifdef QUOTADEBUG#define XQM_LIST_PRINT(l, NXT, title) \{ \	xfs_dquot_t	*dqp; int i = 0; \	cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \	for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \		cmn_err(CE_DEBUG, "   %d.  \"%d (%s)\"   " \				  "bcnt = %d, icnt = %d, refs = %d", \			++i, (int) be32_to_cpu(dqp->q_core.d_id), \			DQFLAGTO_TYPESTR(dqp),	     \			(int) be64_to_cpu(dqp->q_core.d_bcount), \			(int) be64_to_cpu(dqp->q_core.d_icount), \			(int) dqp->q_nrefs);  } \}#else#define XQM_LIST_PRINT(l, NXT, title) do { } while (0)#endif/* * Initialize the XQM structure. * Note that there is not one quota manager per file system. */STATIC struct xfs_qm *xfs_Gqm_init(void){	xfs_dqhash_t	*udqhash, *gdqhash;	xfs_qm_t	*xqm;	uint		i, hsize, flags = KM_SLEEP | KM_MAYFAIL;	/*	 * Initialize the dquot hash tables.	 */	hsize = XFS_QM_HASHSIZE_HIGH;	while (!(udqhash = kmem_zalloc(hsize * sizeof(xfs_dqhash_t), flags))) {		if ((hsize >>= 1) <= XFS_QM_HASHSIZE_LOW)			flags = KM_SLEEP;	}	gdqhash = kmem_zalloc(hsize * sizeof(xfs_dqhash_t), KM_SLEEP);	ndquot = hsize << 8;	xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);	xqm->qm_dqhashmask = hsize - 1;	xqm->qm_usr_dqhtable = udqhash;	xqm->qm_grp_dqhtable = gdqhash;	ASSERT(xqm->qm_usr_dqhtable != NULL);	ASSERT(xqm->qm_grp_dqhtable != NULL);	for (i = 0; i < hsize; i++) {		xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);		xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);	}	/*	 * Freelist of all dquots of all file systems	 */	xfs_qm_freelist_init(&(xqm->qm_dqfreelist));	/*	 * dquot zone. we register our own low-memory callback.	 */	if (!qm_dqzone) {		xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),						"xfs_dquots");		qm_dqzone = xqm->qm_dqzone;	} else		xqm->qm_dqzone = qm_dqzone;	xfs_qm_shaker = kmem_shake_register(xfs_qm_shake);	/*	 * The t_dqinfo portion of transactions.	 */	if (!qm_dqtrxzone) {		xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),						   "xfs_dqtrx");		qm_dqtrxzone = xqm->qm_dqtrxzone;	} else		xqm->qm_dqtrxzone = qm_dqtrxzone;	atomic_set(&xqm->qm_totaldquots, 0);	xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;	xqm->qm_nrefs = 0;#ifdef DEBUG	mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk");#endif	return xqm;}/* * Destroy the global quota manager when its reference count goes to zero. */STATIC voidxfs_qm_destroy(	struct xfs_qm	*xqm){	int		hsize, i;	ASSERT(xqm != NULL);	ASSERT(xqm->qm_nrefs == 0);	kmem_shake_deregister(xfs_qm_shaker);	hsize = xqm->qm_dqhashmask + 1;	for (i = 0; i < hsize; i++) {		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));		xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));	}	kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t));	kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));	xqm->qm_usr_dqhtable = NULL;	xqm->qm_grp_dqhtable = NULL;	xqm->qm_dqhashmask = 0;	xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist));#ifdef DEBUG	mutex_destroy(&qcheck_lock);#endif	kmem_free(xqm, sizeof(xfs_qm_t));}/* * Called at mount time to let XQM know that another file system is * starting quotas. This isn't crucial information as the individual mount * structures are pretty independent, but it helps the XQM keep a * global view of what's going on. *//* ARGSUSED */STATIC intxfs_qm_hold_quotafs_ref(	struct xfs_mount *mp){	/*	 * Need to lock the xfs_Gqm structure for things like this. For example,	 * the structure could disappear between the entry to this routine and	 * a HOLD operation if not locked.	 */	XFS_QM_LOCK(xfs_Gqm);	if (xfs_Gqm == NULL)		xfs_Gqm = xfs_Gqm_init();	/*	 * We can keep a list of all filesystems with quotas mounted for	 * debugging and statistical purposes, but ...	 * Just take a reference and get out.	 */	XFS_QM_HOLD(xfs_Gqm);	XFS_QM_UNLOCK(xfs_Gqm);	return 0;}/* * Release the reference that a filesystem took at mount time, * so that we know when we need to destroy the entire quota manager. *//* ARGSUSED */STATIC voidxfs_qm_rele_quotafs_ref(	struct xfs_mount *mp){	xfs_dquot_t	*dqp, *nextdqp;	ASSERT(xfs_Gqm);	ASSERT(xfs_Gqm->qm_nrefs > 0);	/*	 * Go thru the freelist and destroy all inactive dquots.	 */	xfs_qm_freelist_lock(xfs_Gqm);	for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;	     dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) {		xfs_dqlock(dqp);		nextdqp = dqp->dq_flnext;		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);			xfs_qm_dqdestroy(dqp);		} else {			xfs_dqunlock(dqp);		}		dqp = nextdqp;	}	xfs_qm_freelist_unlock(xfs_Gqm);	/*	 * Destroy the entire XQM. If somebody mounts with quotaon, this'll	 * be restarted.	 */	XFS_QM_LOCK(xfs_Gqm);	XFS_QM_RELE(xfs_Gqm);	if (xfs_Gqm->qm_nrefs == 0) {		xfs_qm_destroy(xfs_Gqm);		xfs_Gqm = NULL;	}	XFS_QM_UNLOCK(xfs_Gqm);}/* * This is called at mount time from xfs_mountfs to initialize the quotainfo * structure and start the global quotamanager (xfs_Gqm) if it hasn't done * so already.	Note that the superblock has not been read in yet. */voidxfs_qm_mount_quotainit(	xfs_mount_t	*mp,	uint		flags){	/*	 * User, projects or group quotas has to be on.	 */	ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA));	/*	 * Initialize the flags in the mount structure. From this point	 * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc.	 * Note that we enforce nothing if accounting is off.	 * ie.	XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF.	 * It isn't necessary to take the quotaoff lock to do this; this is	 * called from mount.	 */	if (flags & XFSMNT_UQUOTA) {		mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);		if (flags & XFSMNT_UQUOTAENF)			mp->m_qflags |= XFS_UQUOTA_ENFD;	}	if (flags & XFSMNT_GQUOTA) {		mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);		if (flags & XFSMNT_GQUOTAENF)			mp->m_qflags |= XFS_OQUOTA_ENFD;	} else if (flags & XFSMNT_PQUOTA) {		mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);		if (flags & XFSMNT_PQUOTAENF)			mp->m_qflags |= XFS_OQUOTA_ENFD;	}}/* * Just destroy the quotainfo structure. */voidxfs_qm_unmount_quotadestroy(	xfs_mount_t	*mp){	if (mp->m_quotainfo)		xfs_qm_destroy_quotainfo(mp);}/* * This is called from xfs_mountfs to start quotas and initialize all * necessary data structures like quotainfo.  This is also responsible for * running a quotacheck as necessary.  We are guaranteed that the superblock * is consistently read in at this point. */intxfs_qm_mount_quotas(	xfs_mount_t	*mp,	int		mfsi_flags){	unsigned long	s;	int		error = 0;	uint		sbf;	/*	 * If quotas on realtime volumes is not supported, we disable	 * quotas immediately.	 */	if (mp->m_sb.sb_rextents) {		cmn_err(CE_NOTE,			"Cannot turn on quotas for realtime filesystem %s",			mp->m_fsname);		mp->m_qflags = 0;		goto write_changes;	}	ASSERT(XFS_IS_QUOTA_RUNNING(mp));	/*	 * Allocate the quotainfo structure inside the mount struct, and	 * create quotainode(s), and change/rev superblock if necessary.	 */	if ((error = xfs_qm_init_quotainfo(mp))) {		/*		 * We must turn off quotas.		 */		ASSERT(mp->m_quotainfo == NULL);		mp->m_qflags = 0;		goto write_changes;	}	/*	 * If any of the quotas are not consistent, do a quotacheck.	 */	if (XFS_QM_NEED_QUOTACHECK(mp) &&		!(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) {		if ((error = xfs_qm_quotacheck(mp))) {			/* Quotacheck has failed and quotas have			 * been disabled.			 */			return XFS_ERROR(error);		}	} write_changes:	/*	 * We actually don't have to acquire the SB_LOCK at all.	 * This can only be called from mount, and that's single threaded. XXX	 */	s = XFS_SB_LOCK(mp);	sbf = mp->m_sb.sb_qflags;	mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;	XFS_SB_UNLOCK(mp, s);	if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {		if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {			/*			 * We could only have been turning quotas off.			 * We aren't in very good shape actually because			 * the incore structures are convinced that quotas are			 * off, but the on disk superblock doesn't know that !			 */			ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));			xfs_fs_cmn_err(CE_ALERT, mp,				"XFS mount_quotas: Superblock update failed!");		}	}	if (error) {		xfs_fs_cmn_err(CE_WARN, mp,			"Failed to initialize disk quotas.");	}	return XFS_ERROR(error);}/* * Called from the vfsops layer. */intxfs_qm_unmount_quotas(	xfs_mount_t	*mp){	xfs_inode_t	*uqp, *gqp;	int		error = 0;	/*	 * Release the dquots that root inode, et al might be holding,	 * before we flush quotas and blow away the quotainfo structure.	 */	ASSERT(mp->m_rootip);	xfs_qm_dqdetach(mp->m_rootip);	if (mp->m_rbmip)		xfs_qm_dqdetach(mp->m_rbmip);	if (mp->m_rsumip)		xfs_qm_dqdetach(mp->m_rsumip);	/*	 * Flush out the quota inodes.	 */	uqp = gqp = NULL;	if (mp->m_quotainfo) {		if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {			xfs_ilock(uqp, XFS_ILOCK_EXCL);			xfs_iflock(uqp);			error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);			xfs_iunlock(uqp, XFS_ILOCK_EXCL);			if (unlikely(error == EFSCORRUPTED)) {				XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",						 XFS_ERRLEVEL_LOW, mp);				goto out;			}		}		if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {			xfs_ilock(gqp, XFS_ILOCK_EXCL);			xfs_iflock(gqp);			error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);			xfs_iunlock(gqp, XFS_ILOCK_EXCL);			if (unlikely(error == EFSCORRUPTED)) {				XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",						 XFS_ERRLEVEL_LOW, mp);				goto out;			}		}	}	if (uqp) {		 XFS_PURGE_INODE(uqp);		 mp->m_quotainfo->qi_uquotaip = NULL;	}	if (gqp) {		XFS_PURGE_INODE(gqp);		mp->m_quotainfo->qi_gquotaip = NULL;	}out:	return XFS_ERROR(error);}/* * Flush all dquots of the given file system to disk. The dquots are * _not_ purged from memory here, just their data written to disk. */STATIC intxfs_qm_dqflush_all(	xfs_mount_t	*mp,	int		flags){	int		recl;	xfs_dquot_t	*dqp;	int		niters;	int		error;	if (mp->m_quotainfo == NULL)		return (0);	niters = 0;again:	xfs_qm_mplist_lock(mp);	FOREACH_DQUOT_IN_MP(dqp, mp) {		xfs_dqlock(dqp);		if (! XFS_DQ_IS_DIRTY(dqp)) {			xfs_dqunlock(dqp);			continue;		}		xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY");		/* XXX a sentinel would be better */		recl = XFS_QI_MPLRECLAIMS(mp);		if (! xfs_qm_dqflock_nowait(dqp)) {			/*			 * If we can't grab the flush lock then check			 * to see if the dquot has been flushed delayed			 * write.  If so, grab its buffer and send it			 * out immediately.  We'll be able to acquire			 * the flush lock when the I/O completes.

⌨️ 快捷键说明

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