Long-promised cleanup: lock_super(sb);unlock_super(sb); is gone from
get_super(). ->s_umount gives all needed exclusion.
And here comes the rest of ->s_count story: we lump all permanent references
together, but now we count them as 1+BIGNUM. Now conversion of temporary
reference to permanent one can recognize dying superblocks by s_count alone.
We don't have to rely on mount_sem for that. Check grab_super() and the very
beginning of kill_super() for details - it's quite straightforward. That's
where we need atomicity of s_active, BTW.
diff -urN S9-pre1-dquot/fs/super.c S9-pre1-s_count/fs/super.c
--- S9-pre1-dquot/fs/super.c	Sun Aug 12 20:45:51 2001
+++ S9-pre1-s_count/fs/super.c	Sun Aug 12 20:45:52 2001
@@ -732,10 +732,6 @@
 	s = find_super(dev);
 	if (s) {
 		spin_unlock(&sb_lock);
-		/* Yes, it sucks. As soon as we get refcounting... */
-		/* Almost there - next two lines will go away RSN */
-		lock_super(s);
-		unlock_super(s);
 		down_read(&s->s_umount);
 		if (s->s_root)
 			return s;
@@ -818,6 +814,7 @@
 	spin_lock(&sb_lock);
 	list_add (&s->s_list, super_blocks.prev);
 	list_add (&s->s_instances, &type->fs_supers);
+	s->s_count += S_BIAS;
 	spin_unlock(&sb_lock);
 	down_write(&s->s_umount);
 	lock_super(s);
@@ -839,6 +836,7 @@
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
 	list_del(&s->s_instances);
+	s->s_count -= S_BIAS;
 	spin_unlock(&sb_lock);
 	put_super(s);
 	return NULL;
@@ -879,13 +877,13 @@
 	spin_unlock(&sb_lock);
 	down_write(&sb->s_umount);
 	if (sb->s_root) {
-		/* Still relying on mount_sem */
-		if (atomic_read(&sb->s_active) > 1) {
-			spin_lock(&sb_lock);
+		spin_lock(&sb_lock);
+		if (sb->s_count > S_BIAS) {
 			sb->s_count--;
 			spin_unlock(&sb_lock);
 			return 1;
 		}
+		spin_unlock(&sb_lock);
 	}
 	atomic_dec(&sb->s_active);
 	put_super(sb);
@@ -970,6 +968,7 @@
 	s->s_type = fs_type;
 	list_add (&s->s_list, super_blocks.prev);
 	list_add (&s->s_instances, &fs_type->fs_supers);
+	s->s_count += S_BIAS;
 
 	spin_unlock(&sb_lock);
 
@@ -993,6 +992,7 @@
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
 	list_del(&s->s_instances);
+	s->s_count -= S_BIAS;
 	spin_unlock(&sb_lock);
 	put_super(s);
 out1:
@@ -1061,6 +1061,7 @@
 		s->s_type = fs_type;
 		list_add (&s->s_list, super_blocks.prev);
 		list_add (&s->s_instances, &fs_type->fs_supers);
+		s->s_count += S_BIAS;
 		spin_unlock(&sb_lock);
 		lock_super(s);
 		if (!fs_type->read_super(s, data, 0))
@@ -1078,6 +1079,7 @@
 		spin_lock(&sb_lock);
 		list_del(&s->s_list);
 		list_del(&s->s_instances);
+		s->s_count -= S_BIAS;
 		spin_unlock(&sb_lock);
 		put_super(s);
 		put_unnamed_dev(dev);
@@ -1094,8 +1096,12 @@
 	struct file_system_type *fs = sb->s_type;
 	struct super_operations *sop = sb->s_op;
 
-	if (!atomic_dec_and_test(&sb->s_active))
+	if (!atomic_dec_and_lock(&sb->s_active, &sb_lock))
 		return;
+
+	sb->s_count -= S_BIAS;
+	spin_unlock(&sb_lock);
+
 	down_write(&sb->s_umount);
 	lock_kernel();
 	sb->s_root = NULL;
diff -urN S9-pre1-dquot/include/linux/fs.h S9-pre1-s_count/include/linux/fs.h
--- S9-pre1-dquot/include/linux/fs.h	Sun Aug 12 20:45:51 2001
+++ S9-pre1-s_count/include/linux/fs.h	Sun Aug 12 20:45:52 2001
@@ -660,6 +660,7 @@
 extern spinlock_t sb_lock;
 
 #define sb_entry(list)	list_entry((list), struct super_block, s_list)
+#define S_BIAS (1<<30)
 struct super_block {
 	struct list_head	s_list;		/* Keep this first */
 	kdev_t			s_dev;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/