|
@@ -121,13 +121,23 @@ static unsigned long super_cache_count(struct shrinker *shrink,
|
|
|
sb = container_of(shrink, struct super_block, s_shrink);
|
|
|
|
|
|
/*
|
|
|
- * Don't call trylock_super as it is a potential
|
|
|
- * scalability bottleneck. The counts could get updated
|
|
|
- * between super_cache_count and super_cache_scan anyway.
|
|
|
- * Call to super_cache_count with shrinker_rwsem held
|
|
|
- * ensures the safety of call to list_lru_shrink_count() and
|
|
|
- * s_op->nr_cached_objects().
|
|
|
+ * We don't call trylock_super() here as it is a scalability bottleneck,
|
|
|
+ * so we're exposed to partial setup state. The shrinker rwsem does not
|
|
|
+ * protect filesystem operations backing list_lru_shrink_count() or
|
|
|
+ * s_op->nr_cached_objects(). Counts can change between
|
|
|
+ * super_cache_count and super_cache_scan, so we really don't need locks
|
|
|
+ * here.
|
|
|
+ *
|
|
|
+ * However, if we are currently mounting the superblock, the underlying
|
|
|
+ * filesystem might be in a state of partial construction and hence it
|
|
|
+ * is dangerous to access it. trylock_super() uses a SB_BORN check to
|
|
|
+ * avoid this situation, so do the same here. The memory barrier is
|
|
|
+ * matched with the one in mount_fs() as we don't hold locks here.
|
|
|
*/
|
|
|
+ if (!(sb->s_flags & SB_BORN))
|
|
|
+ return 0;
|
|
|
+ smp_rmb();
|
|
|
+
|
|
|
if (sb->s_op && sb->s_op->nr_cached_objects)
|
|
|
total_objects = sb->s_op->nr_cached_objects(sb, sc);
|
|
|
|
|
@@ -1272,6 +1282,14 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
|
|
|
sb = root->d_sb;
|
|
|
BUG_ON(!sb);
|
|
|
WARN_ON(!sb->s_bdi);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Write barrier is for super_cache_count(). We place it before setting
|
|
|
+ * SB_BORN as the data dependency between the two functions is the
|
|
|
+ * superblock structure contents that we just set up, not the SB_BORN
|
|
|
+ * flag.
|
|
|
+ */
|
|
|
+ smp_wmb();
|
|
|
sb->s_flags |= SB_BORN;
|
|
|
|
|
|
error = security_sb_kern_mount(sb, flags, secdata);
|