static int v2_read_dquot(struct dquot *dquot)
{
- return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
+ struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
+ int ret;
+
+ down_read(&dqopt->dqio_sem);
+ ret = qtree_read_dquot(
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
+ dquot);
+ up_read(&dqopt->dqio_sem);
+ return ret;
}
static int v2_write_dquot(struct dquot *dquot)
{
- return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
+ struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
+ int ret;
+ bool alloc = false;
+
+ /*
+ * If space for dquot is already allocated, we don't need any
+ * protection as we'll only overwrite the place of dquot. We are
+ * still protected by concurrent writes of the same dquot by
+ * dquot->dq_lock.
+ */
+ if (!dquot->dq_off) {
+ alloc = true;
+ down_write(&dqopt->dqio_sem);
+ }
+ ret = qtree_write_dquot(
+ sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
+ dquot);
+ if (alloc)
+ up_write(&dqopt->dqio_sem);
+ return ret;
}
static int v2_release_dquot(struct dquot *dquot)