|
@@ -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;
|
|
|
}
|