summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-02-18 13:20:20 +0100
committerJan Kara <jack@suse.cz>2016-02-18 13:34:41 +0100
commit044c9b6753a6b6cf486e16b53296b4707b35dbe3 (patch)
tree4854ad052572bab2d07d6d74b247d0017b177452
parentocfs2: Implement get_next_id() (diff)
downloadlinux-044c9b6753a6b6cf486e16b53296b4707b35dbe3.tar.xz
linux-044c9b6753a6b6cf486e16b53296b4707b35dbe3.zip
quota: Fix possible races during quota loading
When loading new quota structure from disk, there is a possibility caller of dqget() will see uninitialized data due to CPU reordering loads or stores - loads from dquot can be reordered before test of DQ_ACTIVE_B bit or setting of this bit could be reordered before filling of the structure. Fix the issue by adding proper memory barriers. Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/quota/dquot.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 7e0137bde6d6..e8467dc90c7e 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -411,6 +411,8 @@ int dquot_acquire(struct dquot *dquot)
ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
if (ret < 0)
goto out_iolock;
+ /* Make sure flags update is visible after dquot has been filled */
+ smp_mb__before_atomic();
set_bit(DQ_READ_B, &dquot->dq_flags);
/* Instantiate dquot if needed */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
@@ -427,6 +429,11 @@ int dquot_acquire(struct dquot *dquot)
goto out_iolock;
}
}
+ /*
+ * Make sure flags update is visible after on-disk struct has been
+ * allocated. Paired with smp_rmb() in dqget().
+ */
+ smp_mb__before_atomic();
set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
out_iolock:
mutex_unlock(&dqopt->dqio_mutex);
@@ -887,6 +894,11 @@ we_slept:
goto out;
}
}
+ /*
+ * Make sure following reads see filled structure - paired with
+ * smp_mb__before_atomic() in dquot_acquire().
+ */
+ smp_rmb();
#ifdef CONFIG_QUOTA_DEBUG
BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */
#endif