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

📄 xfs_dquot.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2000-2003 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_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_bmap.h"#include "xfs_rtalloc.h"#include "xfs_error.h"#include "xfs_itable.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_trans_priv.h"#include "xfs_qm.h"/*   LOCK ORDER   inode lock		    (ilock)   dquot hash-chain lock    (hashlock)   xqm dquot freelist lock  (freelistlock   mount's dquot list lock  (mplistlock)   user dquot lock - lock ordering among dquots is based on the uid or gid   group dquot lock - similar to udquots. Between the two dquots, the udquot		      has to be locked first.   pin lock - the dquot lock must be held to take this lock.   flush lock - ditto.*/STATIC void		xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);#ifdef DEBUGxfs_buftarg_t *xfs_dqerror_target;int xfs_do_dqerror;int xfs_dqreq_num;int xfs_dqerror_mod = 33;#endif/* * Allocate and initialize a dquot. We don't always allocate fresh memory; * we try to reclaim a free dquot if the number of incore dquots are above * a threshold. * The only field inside the core that gets initialized at this point * is the d_id field. The idea is to fill in the entire q_core * when we read in the on disk dquot. */STATIC xfs_dquot_t *xfs_qm_dqinit(	xfs_mount_t  *mp,	xfs_dqid_t   id,	uint	     type){	xfs_dquot_t	*dqp;	boolean_t	brandnewdquot;	brandnewdquot = xfs_qm_dqalloc_incore(&dqp);	dqp->dq_flags = type;	dqp->q_core.d_id = cpu_to_be32(id);	dqp->q_mount = mp;	/*	 * No need to re-initialize these if this is a reclaimed dquot.	 */	if (brandnewdquot) {		dqp->dq_flnext = dqp->dq_flprev = dqp;		mutex_init(&dqp->q_qlock,  MUTEX_DEFAULT, "xdq");		initnsema(&dqp->q_flock, 1, "fdq");		sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");#ifdef XFS_DQUOT_TRACE		dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP);		xfs_dqtrace_entry(dqp, "DQINIT");#endif	} else {		/*		 * Only the q_core portion was zeroed in dqreclaim_one().		 * So, we need to reset others.		 */		 dqp->q_nrefs = 0;		 dqp->q_blkno = 0;		 dqp->MPL_NEXT = dqp->HL_NEXT = NULL;		 dqp->HL_PREVP = dqp->MPL_PREVP = NULL;		 dqp->q_bufoffset = 0;		 dqp->q_fileoffset = 0;		 dqp->q_transp = NULL;		 dqp->q_gdquot = NULL;		 dqp->q_res_bcount = 0;		 dqp->q_res_icount = 0;		 dqp->q_res_rtbcount = 0;		 dqp->q_pincount = 0;		 dqp->q_hash = NULL;		 ASSERT(dqp->dq_flnext == dqp->dq_flprev);#ifdef XFS_DQUOT_TRACE		 ASSERT(dqp->q_trace);		 xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");#endif	 }	/*	 * log item gets initialized later	 */	return (dqp);}/* * This is called to free all the memory associated with a dquot */voidxfs_qm_dqdestroy(	xfs_dquot_t	*dqp){	ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp));	mutex_destroy(&dqp->q_qlock);	freesema(&dqp->q_flock);	sv_destroy(&dqp->q_pinwait);#ifdef XFS_DQUOT_TRACE	if (dqp->q_trace)	     ktrace_free(dqp->q_trace);	dqp->q_trace = NULL;#endif	kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);	atomic_dec(&xfs_Gqm->qm_totaldquots);}/* * This is what a 'fresh' dquot inside a dquot chunk looks like on disk. */STATIC voidxfs_qm_dqinit_core(	xfs_dqid_t	id,	uint		type,	xfs_dqblk_t	*d){	/*	 * Caller has zero'd the entire dquot 'chunk' already.	 */	d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);	d->dd_diskdq.d_version = XFS_DQUOT_VERSION;	d->dd_diskdq.d_id = cpu_to_be32(id);	d->dd_diskdq.d_flags = type;}#ifdef XFS_DQUOT_TRACE/* * Dquot tracing for debugging. *//* ARGSUSED */void__xfs_dqtrace_entry(	xfs_dquot_t	*dqp,	char		*func,	void		*retaddr,	xfs_inode_t	*ip){	xfs_dquot_t	*udqp = NULL;	xfs_ino_t	ino = 0;	ASSERT(dqp->q_trace);	if (ip) {		ino = ip->i_ino;		udqp = ip->i_udquot;	}	ktrace_enter(dqp->q_trace,		     (void *)(__psint_t)DQUOT_KTRACE_ENTRY,		     (void *)func,		     (void *)(__psint_t)dqp->q_nrefs,		     (void *)(__psint_t)dqp->dq_flags,		     (void *)(__psint_t)dqp->q_res_bcount,		     (void *)(__psint_t)be64_to_cpu(dqp->q_core.d_bcount),		     (void *)(__psint_t)be64_to_cpu(dqp->q_core.d_icount),		     (void *)(__psint_t)be64_to_cpu(dqp->q_core.d_blk_hardlimit),		     (void *)(__psint_t)be64_to_cpu(dqp->q_core.d_blk_softlimit),		     (void *)(__psint_t)be64_to_cpu(dqp->q_core.d_ino_hardlimit),		     (void *)(__psint_t)be64_to_cpu(dqp->q_core.d_ino_softlimit),		     (void *)(__psint_t)be32_to_cpu(dqp->q_core.d_id),		     (void *)(__psint_t)current_pid(),		     (void *)(__psint_t)ino,		     (void *)(__psint_t)retaddr,		     (void *)(__psint_t)udqp);	return;}#endif/* * If default limits are in force, push them into the dquot now. * We overwrite the dquot limits only if they are zero and this * is not the root dquot. */voidxfs_qm_adjust_dqlimits(	xfs_mount_t		*mp,	xfs_disk_dquot_t	*d){	xfs_quotainfo_t		*q = mp->m_quotainfo;	ASSERT(d->d_id);	if (q->qi_bsoftlimit && !d->d_blk_softlimit)		d->d_blk_softlimit = cpu_to_be64(q->qi_bsoftlimit);	if (q->qi_bhardlimit && !d->d_blk_hardlimit)		d->d_blk_hardlimit = cpu_to_be64(q->qi_bhardlimit);	if (q->qi_isoftlimit && !d->d_ino_softlimit)		d->d_ino_softlimit = cpu_to_be64(q->qi_isoftlimit);	if (q->qi_ihardlimit && !d->d_ino_hardlimit)		d->d_ino_hardlimit = cpu_to_be64(q->qi_ihardlimit);	if (q->qi_rtbsoftlimit && !d->d_rtb_softlimit)		d->d_rtb_softlimit = cpu_to_be64(q->qi_rtbsoftlimit);	if (q->qi_rtbhardlimit && !d->d_rtb_hardlimit)		d->d_rtb_hardlimit = cpu_to_be64(q->qi_rtbhardlimit);}/* * Check the limits and timers of a dquot and start or reset timers * if necessary. * This gets called even when quota enforcement is OFF, which makes our * life a little less complicated. (We just don't reject any quota * reservations in that case, when enforcement is off). * We also return 0 as the values of the timers in Q_GETQUOTA calls, when * enforcement's off. * In contrast, warnings are a little different in that they don't * 'automatically' get started when limits get exceeded.  They do * get reset to zero, however, when we find the count to be under * the soft limit (they are only ever set non-zero via userspace). */voidxfs_qm_adjust_dqtimers(	xfs_mount_t		*mp,	xfs_disk_dquot_t	*d){	ASSERT(d->d_id);#ifdef QUOTADEBUG	if (d->d_blk_hardlimit)		ASSERT(be64_to_cpu(d->d_blk_softlimit) <=		       be64_to_cpu(d->d_blk_hardlimit));	if (d->d_ino_hardlimit)		ASSERT(be64_to_cpu(d->d_ino_softlimit) <=		       be64_to_cpu(d->d_ino_hardlimit));	if (d->d_rtb_hardlimit)		ASSERT(be64_to_cpu(d->d_rtb_softlimit) <=		       be64_to_cpu(d->d_rtb_hardlimit));#endif	if (!d->d_btimer) {		if ((d->d_blk_softlimit &&		     (be64_to_cpu(d->d_bcount) >=		      be64_to_cpu(d->d_blk_softlimit))) ||		    (d->d_blk_hardlimit &&		     (be64_to_cpu(d->d_bcount) >=		      be64_to_cpu(d->d_blk_hardlimit)))) {			d->d_btimer = cpu_to_be32(get_seconds() +					XFS_QI_BTIMELIMIT(mp));		} else {			d->d_bwarns = 0;		}	} else {		if ((!d->d_blk_softlimit ||		     (be64_to_cpu(d->d_bcount) <		      be64_to_cpu(d->d_blk_softlimit))) &&		    (!d->d_blk_hardlimit ||		    (be64_to_cpu(d->d_bcount) <		     be64_to_cpu(d->d_blk_hardlimit)))) {			d->d_btimer = 0;		}	}	if (!d->d_itimer) {		if ((d->d_ino_softlimit &&		     (be64_to_cpu(d->d_icount) >=		      be64_to_cpu(d->d_ino_softlimit))) ||		    (d->d_ino_hardlimit &&		     (be64_to_cpu(d->d_icount) >=		      be64_to_cpu(d->d_ino_hardlimit)))) {			d->d_itimer = cpu_to_be32(get_seconds() +					XFS_QI_ITIMELIMIT(mp));		} else {			d->d_iwarns = 0;		}	} else {		if ((!d->d_ino_softlimit ||		     (be64_to_cpu(d->d_icount) <		      be64_to_cpu(d->d_ino_softlimit)))  &&		    (!d->d_ino_hardlimit ||		     (be64_to_cpu(d->d_icount) <		      be64_to_cpu(d->d_ino_hardlimit)))) {			d->d_itimer = 0;		}	}	if (!d->d_rtbtimer) {		if ((d->d_rtb_softlimit &&		     (be64_to_cpu(d->d_rtbcount) >=		      be64_to_cpu(d->d_rtb_softlimit))) ||		    (d->d_rtb_hardlimit &&		     (be64_to_cpu(d->d_rtbcount) >=		      be64_to_cpu(d->d_rtb_hardlimit)))) {			d->d_rtbtimer = cpu_to_be32(get_seconds() +					XFS_QI_RTBTIMELIMIT(mp));		} else {			d->d_rtbwarns = 0;		}	} else {		if ((!d->d_rtb_softlimit ||		     (be64_to_cpu(d->d_rtbcount) <		      be64_to_cpu(d->d_rtb_softlimit))) &&		    (!d->d_rtb_hardlimit ||		     (be64_to_cpu(d->d_rtbcount) <		      be64_to_cpu(d->d_rtb_hardlimit)))) {			d->d_rtbtimer = 0;		}	}}/* * initialize a buffer full of dquots and log the whole thing */STATIC voidxfs_qm_init_dquot_blk(	xfs_trans_t	*tp,	xfs_mount_t	*mp,	xfs_dqid_t	id,	uint		type,	xfs_buf_t	*bp){	xfs_dqblk_t	*d;	int		curid, i;	ASSERT(tp);	ASSERT(XFS_BUF_ISBUSY(bp));	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);	d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);	/*	 * ID of the first dquot in the block - id's are zero based.	 */	curid = id - (id % XFS_QM_DQPERBLK(mp));	ASSERT(curid >= 0);	memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));	for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)		xfs_qm_dqinit_core(curid, type, d);	xfs_trans_dquot_buf(tp, bp,			    (type & XFS_DQ_USER ? XFS_BLI_UDQUOT_BUF :			    ((type & XFS_DQ_PROJ) ? XFS_BLI_PDQUOT_BUF :			     XFS_BLI_GDQUOT_BUF)));	xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);}/* * Allocate a block and fill it with dquots. * This is called when the bmapi finds a hole. */STATIC intxfs_qm_dqalloc(	xfs_trans_t	**tpp,	xfs_mount_t	*mp,	xfs_dquot_t	*dqp,	xfs_inode_t	*quotip,	xfs_fileoff_t	offset_fsb,	xfs_buf_t	**O_bpp){	xfs_fsblock_t	firstblock;	xfs_bmap_free_t flist;	xfs_bmbt_irec_t map;	int		nmaps, error, committed;	xfs_buf_t	*bp;	xfs_trans_t	*tp = *tpp;	ASSERT(tp != NULL);	xfs_dqtrace_entry(dqp, "DQALLOC");	/*	 * Initialize the bmap freelist prior to calling bmapi code.	 */	XFS_BMAP_INIT(&flist, &firstblock);	xfs_ilock(quotip, XFS_ILOCK_EXCL);	/*	 * Return if this type of quotas is turned off while we didn't	 * have an inode lock	 */	if (XFS_IS_THIS_QUOTA_OFF(dqp)) {		xfs_iunlock(quotip, XFS_ILOCK_EXCL);		return (ESRCH);	}	/*	 * xfs_trans_commit normally decrements the vnode ref count	 * when it unlocks the inode. Since we want to keep the quota	 * inode around, we bump the vnode ref count now.	 */	VN_HOLD(XFS_ITOV(quotip));	xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);	nmaps = 1;	if ((error = xfs_bmapi(tp, quotip,			      offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,			      XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,			      &firstblock,			      XFS_QM_DQALLOC_SPACE_RES(mp),			      &map, &nmaps, &flist))) {		goto error0;	}	ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);	ASSERT(nmaps == 1);	ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&	       (map.br_startblock != HOLESTARTBLOCK));	/*	 * Keep track of the blkno to save a lookup later	 */	dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);	/* now we can just get the buffer (there's nothing to read yet) */	bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,			       dqp->q_blkno,			       XFS_QI_DQCHUNKLEN(mp),			       0);	if (!bp || (error = XFS_BUF_GETERROR(bp)))		goto error1;	/*	 * Make a chunk of dquots out of this buffer and log	 * the entire thing.	 */	xfs_qm_init_dquot_blk(tp, mp, be32_to_cpu(dqp->q_core.d_id),			      dqp->dq_flags & XFS_DQ_ALLTYPES, bp);	/*	 * xfs_bmap_finish() may commit the current transaction and	 * start a second transaction if the freelist is not empty.	 *	 * Since we still want to modify this buffer, we need to	 * ensure that the buffer is not released on commit of	 * the first transaction and ensure the buffer is added to the	 * second transaction.	 *	 * If there is only one transaction then don't stop the buffer	 * from being released when it commits later on.	 */	xfs_trans_bhold(tp, bp);	if ((error = xfs_bmap_finish(tpp, &flist, firstblock, &committed))) {		goto error1;	}	if (committed) {		tp = *tpp;		xfs_trans_bjoin(tp, bp);	} else {		xfs_trans_bhold_release(tp, bp);	}	*O_bpp = bp;	return 0;      error1:	xfs_bmap_cancel(&flist);      error0:	xfs_iunlock(quotip, XFS_ILOCK_EXCL);	return (error);}/* * Maps a dquot to the buffer containing its on-disk version. * This returns a ptr to the buffer containing the on-disk dquot * in the bpp param, and a ptr to the on-disk dquot within that buffer */STATIC intxfs_qm_dqtobp(	xfs_trans_t		**tpp,	xfs_dquot_t		*dqp,	xfs_disk_dquot_t	**O_ddpp,	xfs_buf_t		**O_bpp,	uint			flags){	xfs_bmbt_irec_t map;	int		nmaps, error;	xfs_buf_t	*bp;	xfs_inode_t	*quotip;	xfs_mount_t	*mp;	xfs_disk_dquot_t *ddq;	xfs_dqid_t	id;	boolean_t	newdquot;	xfs_trans_t	*tp = (tpp ? *tpp : NULL);	mp = dqp->q_mount;

⌨️ 快捷键说明

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