xfs: implement lazy removal for the dquot freelist
Do not remove dquots from the freelist when we grab a reference to them in xfs_qm_dqlookup, but leave them on the freelist util scanning notices that they have a reference. This speeds up the lookup fastpath, and greatly simplifies the lock ordering constraints. Note that the same scheme is used by the VFS inode and dentry caches. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
		
							parent
							
								
									80a376bfb7
								
							
						
					
					
						commit
						be7ffc38a8
					
				| @ -722,58 +722,25 @@ xfs_qm_dqlookup( | ||||
| 		 * 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) { | ||||
| 			trace_xfs_dqlookup_found(dqp); | ||||
| 		if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp) | ||||
| 			continue; | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * All in core dquots must be on the dqlist of mp | ||||
| 			 */ | ||||
| 			ASSERT(!list_empty(&dqp->q_mplist)); | ||||
| 		trace_xfs_dqlookup_found(dqp); | ||||
| 
 | ||||
| 			xfs_dqlock(dqp); | ||||
| 			if (dqp->q_nrefs == 0) { | ||||
| 				ASSERT(!list_empty(&dqp->q_freelist)); | ||||
| 				if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) { | ||||
| 					trace_xfs_dqlookup_want(dqp); | ||||
| 		xfs_dqlock(dqp); | ||||
| 		XFS_DQHOLD(dqp); | ||||
| 
 | ||||
| 					/*
 | ||||
| 					 * 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); | ||||
| 					mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); | ||||
| 					xfs_dqlock(dqp); | ||||
| 					dqp->dq_flags &= ~(XFS_DQ_WANT); | ||||
| 				} | ||||
| 
 | ||||
| 				if (dqp->q_nrefs == 0) { | ||||
| 					/* take it off the freelist */ | ||||
| 					trace_xfs_dqlookup_freelist(dqp); | ||||
| 					list_del_init(&dqp->q_freelist); | ||||
| 					xfs_Gqm->qm_dqfrlist_cnt--; | ||||
| 				} | ||||
| 				XFS_DQHOLD(dqp); | ||||
| 				mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock); | ||||
| 			} else { | ||||
| 				XFS_DQHOLD(dqp); | ||||
| 			} | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * move the dquot to the front of the hashchain | ||||
| 			 */ | ||||
| 			ASSERT(mutex_is_locked(&qh->qh_lock)); | ||||
| 			list_move(&dqp->q_hashlist, &qh->qh_list); | ||||
| 			trace_xfs_dqlookup_done(dqp); | ||||
| 			*O_dqpp = dqp; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		/*
 | ||||
| 		 * move the dquot to the front of the hashchain | ||||
| 		 */ | ||||
| 		list_move(&dqp->q_hashlist, &qh->qh_list); | ||||
| 		trace_xfs_dqlookup_done(dqp); | ||||
| 		*O_dqpp = dqp; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	*O_dqpp = NULL; | ||||
| 	ASSERT(mutex_is_locked(&qh->qh_lock)); | ||||
| 	return (1); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -1033,8 +1000,10 @@ xfs_qm_dqput( | ||||
| 		if (--dqp->q_nrefs == 0) { | ||||
| 			trace_xfs_dqput_free(dqp); | ||||
| 
 | ||||
| 			list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist); | ||||
| 			xfs_Gqm->qm_dqfrlist_cnt++; | ||||
| 			if (list_empty(&dqp->q_freelist)) { | ||||
| 				list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist); | ||||
| 				xfs_Gqm->qm_dqfrlist_cnt++; | ||||
| 			} | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * If we just added a udquot to the freelist, then | ||||
|  | ||||
| @ -517,13 +517,12 @@ xfs_qm_dqpurge_int( | ||||
| 	 * get them off mplist and hashlist, but leave them on freelist. | ||||
| 	 */ | ||||
| 	list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) { | ||||
| 		/*
 | ||||
| 		 * 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) | ||||
| 		xfs_dqlock(dqp); | ||||
| 		if ((dqp->dq_flags & dqtype) == 0) { | ||||
| 			xfs_dqunlock(dqp); | ||||
| 			continue; | ||||
| 		} | ||||
| 		xfs_dqunlock(dqp); | ||||
| 
 | ||||
| 		if (!mutex_trylock(&dqp->q_hash->qh_lock)) { | ||||
| 			nrecl = q->qi_dqreclaims; | ||||
| @ -1692,14 +1691,15 @@ again: | ||||
| 		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. | ||||
| 		 * This dquot has already been grabbed by dqlookup. | ||||
| 		 * Remove it from the freelist and try again. | ||||
| 		 */ | ||||
| 		if (dqp->dq_flags & XFS_DQ_WANT) { | ||||
| 		if (dqp->q_nrefs) { | ||||
| 			trace_xfs_dqreclaim_want(dqp); | ||||
| 			XQM_STATS_INC(xqmstats.xs_qm_dqwants); | ||||
| 
 | ||||
| 			list_del_init(&dqp->q_freelist); | ||||
| 			xfs_Gqm->qm_dqfrlist_cnt--; | ||||
| 			restarts++; | ||||
| 			startagain = 1; | ||||
| 			goto dqunlock; | ||||
|  | ||||
| @ -87,7 +87,6 @@ typedef struct xfs_dqblk { | ||||
| #define XFS_DQ_PROJ		0x0002		/* project quota */ | ||||
| #define XFS_DQ_GROUP		0x0004		/* a group quota */ | ||||
| #define XFS_DQ_DIRTY		0x0008		/* dquot is dirty */ | ||||
| #define XFS_DQ_WANT		0x0010		/* for lookup/reclaim race */ | ||||
| 
 | ||||
| #define XFS_DQ_ALLTYPES		(XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) | ||||
| 
 | ||||
| @ -95,8 +94,7 @@ typedef struct xfs_dqblk { | ||||
| 	{ XFS_DQ_USER,		"USER" }, \ | ||||
| 	{ XFS_DQ_PROJ,		"PROJ" }, \ | ||||
| 	{ XFS_DQ_GROUP,		"GROUP" }, \ | ||||
| 	{ XFS_DQ_DIRTY,		"DIRTY" }, \ | ||||
| 	{ XFS_DQ_WANT,		"WANT" } | ||||
| 	{ XFS_DQ_DIRTY,		"DIRTY" } | ||||
| 
 | ||||
| /*
 | ||||
|  * In the worst case, when both user and group quotas are on, | ||||
|  | ||||
| @ -743,8 +743,6 @@ DEFINE_DQUOT_EVENT(xfs_dqtobp_read); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqread); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqread_fail); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqlookup_found); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqlookup_want); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqlookup_freelist); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqlookup_done); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqget_hit); | ||||
| DEFINE_DQUOT_EVENT(xfs_dqget_miss); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user