[PATCHv5 04/16] VFS: add memory barrier to sb_mark_clean and sb_mark_dirty

From: Artem Bityutskiy
Date: Sun Jun 06 2010 - 10:57:07 EST


From: Artem Bityutskiy <Artem.Bityutskiy@xxxxxxxxx>

The proper way for file-systems to synchronize the superblock
should be as follows:

1. when modifying the SB, first modify it, then mark it as dirty;
2. when synchronizing the SB, first mark as clean, then start
synchronizing.

And to make ensure the order, we need memory barriers in 'sb_mark_clean()'
and 'sb_mark_dirty()'.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@xxxxxxxxx>
---
include/linux/fs.h | 14 ++++++++++++++
mm/backing-dev.c | 5 +++++
2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/include/linux/fs.h b/include/linux/fs.h
index ca1e993..3acaccf 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1783,10 +1783,24 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
struct vfsmount *mnt);
extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);

+/*
+ * The SB clean/dirty state manipulations should be done as follows:
+ * 1. modification: first modify the SB-related data, then mark the SB as
+ * dirty;
+ * 2. synchronization: first mark the SB as clean, then start synchronizing it.
+ *
+ * This order makes sure that races are harmless and we never end up in a
+ * situation when the SB is modified but is nevertheless marked as clean.
+ */
void sb_mark_dirty(struct super_block *sb);
static inline void sb_mark_clean(struct super_block *sb)
{
sb->s_dirty = 0;
+ /*
+ * Normally FSes first unset the sb->s_dirty flag, and then start
+ * synchronizing the SB. The memory barrier ensures this order.
+ */
+ smp_mb();
}
static inline int sb_is_dirty(struct super_block *sb)
{
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index d751284..d861bd4 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -352,6 +352,11 @@ static void bdi_flush_io(struct backing_dev_info *bdi)

void sb_mark_dirty(struct super_block *sb)
{
+ /*
+ * Normally FSes modify the SB, and then mark it as dirty. The memory
+ * barrier ensures this order.
+ */
+ smp_mb();
sb->s_dirty = 1;
/*
* sb->s_dirty store must be visible to sync_supers before we load
--
1.7.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/