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

📄 xfs_dquot.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	id = be32_to_cpu(dqp->q_core.d_id);	nmaps = 1;	newdquot = B_FALSE;	/*	 * If we don't know where the dquot lives, find out.	 */	if (dqp->q_blkno == (xfs_daddr_t) 0) {		/* We use the id as an index */		dqp->q_fileoffset = (xfs_fileoff_t)id / XFS_QM_DQPERBLK(mp);		nmaps = 1;		quotip = XFS_DQ_TO_QIP(dqp);		xfs_ilock(quotip, XFS_ILOCK_SHARED);		/*		 * 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_SHARED);			return (ESRCH);		}		/*		 * Find the block map; no allocations yet		 */		error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,				  XFS_DQUOT_CLUSTER_SIZE_FSB,				  XFS_BMAPI_METADATA,				  NULL, 0, &map, &nmaps, NULL);		xfs_iunlock(quotip, XFS_ILOCK_SHARED);		if (error)			return (error);		ASSERT(nmaps == 1);		ASSERT(map.br_blockcount == 1);		/*		 * offset of dquot in the (fixed sized) dquot chunk.		 */		dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) *			sizeof(xfs_dqblk_t);		if (map.br_startblock == HOLESTARTBLOCK) {			/*			 * We don't allocate unless we're asked to			 */			if (!(flags & XFS_QMOPT_DQALLOC))				return (ENOENT);			ASSERT(tp);			if ((error = xfs_qm_dqalloc(tpp, mp, dqp, quotip,						dqp->q_fileoffset, &bp)))				return (error);			tp = *tpp;			newdquot = B_TRUE;		} else {			/*			 * store the blkno etc so that we don't have to do the			 * mapping all the time			 */			dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);		}	}	ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);	ASSERT(dqp->q_blkno != HOLESTARTBLOCK);	/*	 * Read in the buffer, unless we've just done the allocation	 * (in which case we already have the buf).	 */	if (! newdquot) {		xfs_dqtrace_entry(dqp, "DQTOBP READBUF");		if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,					       dqp->q_blkno,					       XFS_QI_DQCHUNKLEN(mp),					       0, &bp))) {			return (error);		}		if (error || !bp)			return XFS_ERROR(error);	}	ASSERT(XFS_BUF_ISBUSY(bp));	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);	/*	 * calculate the location of the dquot inside the buffer.	 */	ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);	/*	 * A simple sanity check in case we got a corrupted dquot...	 */	if (xfs_qm_dqcheck(ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES,			   flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),			   "dqtobp")) {		if (!(flags & XFS_QMOPT_DQREPAIR)) {			xfs_trans_brelse(tp, bp);			return XFS_ERROR(EIO);		}		XFS_BUF_BUSY(bp); /* We dirtied this */	}	*O_bpp = bp;	*O_ddpp = ddq;	return (0);}/* * Read in the ondisk dquot using dqtobp() then copy it to an incore version, * and release the buffer immediately. * *//* ARGSUSED */STATIC intxfs_qm_dqread(	xfs_trans_t	**tpp,	xfs_dqid_t	id,	xfs_dquot_t	*dqp,	/* dquot to get filled in */	uint		flags){	xfs_disk_dquot_t *ddqp;	xfs_buf_t	 *bp;	int		 error;	xfs_trans_t	 *tp;	ASSERT(tpp);	/*	 * get a pointer to the on-disk dquot and the buffer containing it	 * dqp already knows its own type (GROUP/USER).	 */	xfs_dqtrace_entry(dqp, "DQREAD");	if ((error = xfs_qm_dqtobp(tpp, dqp, &ddqp, &bp, flags))) {		return (error);	}	tp = *tpp;	/* copy everything from disk dquot to the incore dquot */	memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));	ASSERT(be32_to_cpu(dqp->q_core.d_id) == id);	xfs_qm_dquot_logitem_init(dqp);	/*	 * Reservation counters are defined as reservation plus current usage	 * to avoid having to add everytime.	 */	dqp->q_res_bcount = be64_to_cpu(ddqp->d_bcount);	dqp->q_res_icount = be64_to_cpu(ddqp->d_icount);	dqp->q_res_rtbcount = be64_to_cpu(ddqp->d_rtbcount);	/* Mark the buf so that this will stay incore a little longer */	XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);	/*	 * We got the buffer with a xfs_trans_read_buf() (in dqtobp())	 * So we need to release with xfs_trans_brelse().	 * The strategy here is identical to that of inodes; we lock	 * the dquot in xfs_qm_dqget() before making it accessible to	 * others. This is because dquots, like inodes, need a good level of	 * concurrency, and we don't want to take locks on the entire buffers	 * for dquot accesses.	 * Note also that the dquot buffer may even be dirty at this point, if	 * this particular dquot was repaired. We still aren't afraid to	 * brelse it because we have the changes incore.	 */	ASSERT(XFS_BUF_ISBUSY(bp));	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);	xfs_trans_brelse(tp, bp);	return (error);}/* * allocate an incore dquot from the kernel heap, * and fill its core with quota information kept on disk. * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk * if it wasn't already allocated. */STATIC intxfs_qm_idtodq(	xfs_mount_t	*mp,	xfs_dqid_t	id,	 /* gid or uid, depending on type */	uint		type,	 /* UDQUOT or GDQUOT */	uint		flags,	 /* DQALLOC, DQREPAIR */	xfs_dquot_t	**O_dqpp)/* OUT : incore dquot, not locked */{	xfs_dquot_t	*dqp;	int		error;	xfs_trans_t	*tp;	int		cancelflags=0;	dqp = xfs_qm_dqinit(mp, id, type);	tp = NULL;	if (flags & XFS_QMOPT_DQALLOC) {		tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);		if ((error = xfs_trans_reserve(tp,				       XFS_QM_DQALLOC_SPACE_RES(mp),				       XFS_WRITE_LOG_RES(mp) +					      BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 +					      128,				       0,				       XFS_TRANS_PERM_LOG_RES,				       XFS_WRITE_LOG_COUNT))) {			cancelflags = 0;			goto error0;		}		cancelflags = XFS_TRANS_RELEASE_LOG_RES;	}	/*	 * Read it from disk; xfs_dqread() takes care of	 * all the necessary initialization of dquot's fields (locks, etc)	 */	if ((error = xfs_qm_dqread(&tp, id, dqp, flags))) {		/*		 * This can happen if quotas got turned off (ESRCH),		 * or if the dquot didn't exist on disk and we ask to		 * allocate (ENOENT).		 */		xfs_dqtrace_entry(dqp, "DQREAD FAIL");		cancelflags |= XFS_TRANS_ABORT;		goto error0;	}	if (tp) {		if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,					     NULL)))			goto error1;	}	*O_dqpp = dqp;	return (0); error0:	ASSERT(error);	if (tp)		xfs_trans_cancel(tp, cancelflags); error1:	xfs_qm_dqdestroy(dqp);	*O_dqpp = NULL;	return (error);}/* * Lookup a dquot in the incore dquot hashtable. We keep two separate * hashtables for user and group dquots; and, these are global tables * inside the XQM, not per-filesystem tables. * The hash chain must be locked by caller, and it is left locked * on return. Returning dquot is locked. */STATIC intxfs_qm_dqlookup(	xfs_mount_t		*mp,	xfs_dqid_t		id,	xfs_dqhash_t		*qh,	xfs_dquot_t		**O_dqpp){	xfs_dquot_t		*dqp;	uint			flist_locked;	xfs_dquot_t		*d;	ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));	flist_locked = B_FALSE;	/*	 * Traverse the hashchain looking for a match	 */	for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) {		/*		 * We already have the hashlock. We don't need the		 * dqlock to look at the id field of the dquot, since the		 * id can't be modified without the hashlock anyway.		 */		if (be32_to_cpu(dqp->q_core.d_id) == id && dqp->q_mount == mp) {			xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP");			/*			 * All in core dquots must be on the dqlist of mp			 */			ASSERT(dqp->MPL_PREVP != NULL);			xfs_dqlock(dqp);			if (dqp->q_nrefs == 0) {				ASSERT (XFS_DQ_IS_ON_FREELIST(dqp));				if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {					xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT");					/*					 * We may have raced with dqreclaim_one()					 * (and lost). So, flag that we don't					 * want the dquot to be reclaimed.					 */					dqp->dq_flags |= XFS_DQ_WANT;					xfs_dqunlock(dqp);					xfs_qm_freelist_lock(xfs_Gqm);					xfs_dqlock(dqp);					dqp->dq_flags &= ~(XFS_DQ_WANT);				}				flist_locked = B_TRUE;			}			/*			 * id couldn't have changed; we had the hashlock all			 * along			 */			ASSERT(be32_to_cpu(dqp->q_core.d_id) == id);			if (flist_locked) {				if (dqp->q_nrefs != 0) {					xfs_qm_freelist_unlock(xfs_Gqm);					flist_locked = B_FALSE;				} else {					/*					 * take it off the freelist					 */					xfs_dqtrace_entry(dqp,							"DQLOOKUP: TAKEOFF FL");					XQM_FREELIST_REMOVE(dqp);					/* xfs_qm_freelist_print(&(xfs_Gqm->							qm_dqfreelist),							"after removal"); */				}			}			/*			 * grab a reference			 */			XFS_DQHOLD(dqp);			if (flist_locked)				xfs_qm_freelist_unlock(xfs_Gqm);			/*			 * move the dquot to the front of the hashchain			 */			ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));			if (dqp->HL_PREVP != &qh->qh_next) {				xfs_dqtrace_entry(dqp,						  "DQLOOKUP: HASH MOVETOFRONT");				if ((d = dqp->HL_NEXT))					d->HL_PREVP = dqp->HL_PREVP;				*(dqp->HL_PREVP) = d;				d = qh->qh_next;				d->HL_PREVP = &dqp->HL_NEXT;				dqp->HL_NEXT = d;				dqp->HL_PREVP = &qh->qh_next;				qh->qh_next = dqp;			}			xfs_dqtrace_entry(dqp, "LOOKUP END");			*O_dqpp = dqp;			ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));			return (0);		}	}	*O_dqpp = NULL;	ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));	return (1);}/* * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a * a locked dquot, doing an allocation (if requested) as needed. * When both an inode and an id are given, the inode's id takes precedence. * That is, if the id changes while we don't hold the ilock inside this * function, the new dquot is returned, not necessarily the one requested * in the id argument. */intxfs_qm_dqget(	xfs_mount_t	*mp,	xfs_inode_t	*ip,	  /* locked inode (optional) */	xfs_dqid_t	id,	  /* uid/projid/gid depending on type */	uint		type,	  /* XFS_DQ_USER/XFS_DQ_PROJ/XFS_DQ_GROUP */	uint		flags,	  /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */	xfs_dquot_t	**O_dqpp) /* OUT : locked incore dquot */{	xfs_dquot_t	*dqp;	xfs_dqhash_t	*h;	uint		version;	int		error;	ASSERT(XFS_IS_QUOTA_RUNNING(mp));	if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||	    (! XFS_IS_PQUOTA_ON(mp) && type == XFS_DQ_PROJ) ||	    (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {		return (ESRCH);	}	h = XFS_DQ_HASH(mp, id, type);#ifdef DEBUG	if (xfs_do_dqerror) {		if ((xfs_dqerror_target == mp->m_ddev_targp) &&		    (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {			cmn_err(CE_DEBUG, "Returning error in dqget");			return (EIO);		}	}#endif again:#ifdef DEBUG	ASSERT(type == XFS_DQ_USER ||	       type == XFS_DQ_PROJ ||	       type == XFS_DQ_GROUP);	if (ip) {		ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));		if (type == XFS_DQ_USER)			ASSERT(ip->i_udquot == NULL);		else			ASSERT(ip->i_gdquot == NULL);	}#endif	XFS_DQ_HASH_LOCK(h);	/*	 * Look in the cache (hashtable).	 * The chain is kept locked during lookup.	 */	if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {		XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);		/*		 * The dquot was found, moved to the front of the chain,		 * taken off the freelist if it was on it, and locked		 * at this point. Just unlock the hashchain and return.		 */		ASSERT(*O_dqpp);		ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));		XFS_DQ_HASH_UNLOCK(h);		xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");		return (0);	/* success */	}	XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);	/*	 * Dquot cache miss. We don't want to keep the inode lock across	 * a (potential) disk read. Also we don't want to deal with the lock	 * ordering between quotainode and this inode. OTOH, dropping the inode	 * lock here means dealing with a chown that can happen before	 * we re-acquire the lock.	 */	if (ip)		xfs_iunlock(ip, XFS_ILOCK_EXCL);	/*	 * Save the hashchain version stamp, and unlock the chain, so that	 * we don't keep the lock across a disk read	 */	version = h->qh_version;	XFS_DQ_HASH_UNLOCK(h);	/*	 * Allocate the dquot on the kernel heap, and read the ondisk	 * portion off the disk. Also, do all the necessary initialization	 * 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_idtodq(mp, id, type,				  flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|					   XFS_QMOPT_DOWARN),				  &dqp))) {		if (ip)			xfs_ilock(ip, XFS_ILOCK_EXCL);		return (error);	}	/*	 * See if this is mount code calling to look at the overall quota limits	 * which are stored in the id == 0 user or group's dquot.	 * Since we may not have done a quotacheck by this point, just return	 * the dquot without attaching it to any hashtables, lists, etc, or even	 * taking a reference.	 * The caller must dqdestroy this once done.	 */	if (flags & XFS_QMOPT_DQSUSER) {		ASSERT(id == 0);		ASSERT(! ip);		goto dqret;	}	/*	 * Dquot lock comes after hashlock in the lock ordering	 */	if (ip) {		xfs_ilock(ip, XFS_ILOCK_EXCL);		if (! XFS_IS_DQTYPE_ON(mp, type)) {			/* inode stays locked on return */			xfs_qm_dqdestroy(dqp);			return XFS_ERROR(ESRCH);		}		/*		 * A dquot could be attached to this inode by now, since		 * we had dropped the ilock.		 */		if (type == XFS_DQ_USER) {			if (ip->i_udquot) {				xfs_qm_dqdestroy(dqp);				dqp = ip->i_udquot;				xfs_dqlock(dqp);				goto dqret;			}		} else {			if (ip->i_gdquot) {				xfs_qm_dqdestroy(dqp);				dqp = ip->i_gdquot;				xfs_dqlock(dqp);				goto dqret;			}		}	}	/*	 * Hashlock comes after ilock in lock order	 */	XFS_DQ_HASH_LOCK(h);	if (version != h->qh_version) {		xfs_dquot_t *tmpdqp;		/*		 * Now, see if somebody else put the dquot in the		 * hashtable before us. This can happen because we didn't		 * keep the hashchain lock. We don't have to worry about		 * lock order between the two dquots here since dqp isn't		 * on any findable lists yet.		 */		if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {			/*			 * Duplicate found. Just throw away the new dquot			 * and start over.			 */			xfs_qm_dqput(tmpdqp);			XFS_DQ_HASH_UNLOCK(h);			xfs_qm_dqdestroy(dqp);			XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);			goto again;		}

⌨️ 快捷键说明

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