diff options
Diffstat (limited to 'fs/xfs/xfs_qm_syscalls.c')
| -rw-r--r-- | fs/xfs/xfs_qm_syscalls.c | 40 | 
1 files changed, 23 insertions, 17 deletions
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index c41190cad6e..6cdf6ffc36a 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -489,31 +489,36 @@ xfs_qm_scall_setqlim(  	if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)  		return 0; -	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); -	error = xfs_trans_reserve(tp, 0, XFS_QM_SETQLIM_LOG_RES(mp), -				  0, 0, XFS_DEFAULT_LOG_COUNT); -	if (error) { -		xfs_trans_cancel(tp, 0); -		return (error); -	} -  	/*  	 * We don't want to race with a quotaoff so take the quotaoff lock. -	 * (We don't hold an inode lock, so there's nothing else to stop -	 * a quotaoff from happening). (XXXThis doesn't currently happen -	 * because we take the vfslock before calling xfs_qm_sysent). +	 * We don't hold an inode lock, so there's nothing else to stop +	 * a quotaoff from happening.  	 */  	mutex_lock(&q->qi_quotaofflock);  	/* -	 * Get the dquot (locked), and join it to the transaction. -	 * Allocate the dquot if this doesn't exist. +	 * Get the dquot (locked) before we start, as we need to do a +	 * transaction to allocate it if it doesn't exist. Once we have the +	 * dquot, unlock it so we can start the next transaction safely. We hold +	 * a reference to the dquot, so it's safe to do this unlock/lock without +	 * it being reclaimed in the mean time.  	 */ -	if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) { -		xfs_trans_cancel(tp, XFS_TRANS_ABORT); +	error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp); +	if (error) {  		ASSERT(error != ENOENT);  		goto out_unlock;  	} +	xfs_dqunlock(dqp); + +	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); +	error = xfs_trans_reserve(tp, 0, XFS_QM_SETQLIM_LOG_RES(mp), +				  0, 0, XFS_DEFAULT_LOG_COUNT); +	if (error) { +		xfs_trans_cancel(tp, 0); +		goto out_rele; +	} + +	xfs_dqlock(dqp);  	xfs_trans_dqjoin(tp, dqp);  	ddq = &dqp->q_core; @@ -621,9 +626,10 @@ xfs_qm_scall_setqlim(  	xfs_trans_log_dquot(tp, dqp);  	error = xfs_trans_commit(tp, 0); -	xfs_qm_dqrele(dqp); - out_unlock: +out_rele: +	xfs_qm_dqrele(dqp); +out_unlock:  	mutex_unlock(&q->qi_quotaofflock);  	return error;  }  |