linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHes] fs/super.c stuff
@ 2001-06-11  5:32 Alexander Viro
  2001-06-11  5:33 ` [PATCH] fs/super.c stuff (1/10) Alexander Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:32 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

OK. It works here(tm). I'm sending first 10 chunks - about 70% of locking
changes. That's a good intermediate point and I'd rather avoid doing too
large steps.

Contents (patches will go in separate postings):

1, Eliminates mnt_instances and s_mounts. Instead of it we add new field to
struct super_block - s_active. Number of vfsmounts for given superblock,
i.e. number of entries in old s_mounts. Right now all accesses are serialized
by mount_sem, but later we'll need it to be atomic_t.

2. Better handling of s_active. Instead of incrementing it just when we
attach a vfsmount we do that beforehand and decrement if get_sb_... fails.

3. blkdev_put(bdev, BDEV_FS) doesn't touch superblock anymore. Current
callers don't need that (nothing to touch - it's either final kill_super()
or failed read_super()) and having it non-interfering with fs structures
gives us more freedom for get_sb_bdev().

4. pure cosmetics - fs.h contains an extern for function that doesn't exist
(put_super(kdev_t)). Removed.

5. instead of passing sb->s_dev to remove_dquot_ref() and doing get_super()
there we pass sb itself. While we are at it invalidate_dquots() is made
static - nothing outside of dquot.c calls it.

6. drop_super() added. At that stage - empty, we just add calls to balance
those of get_super().

7. First serious part.
	* we add a spinlock (sb_lock) that protects super_blocks list.
	* we add a reference counter to struct super_block. ->s_count.
At that stage we don't use it - only maintain correct value. Logics is
the same as for mm_struct - each temporary reference contributes 1,
all permanent references (from vfsmounts) are lumped together. It's an
int - all accesses are protected by sb_lock.
	At that stage we rely on mount_sem to handle the moments when
we turn a temporary reference into permanent one. That will change,
but we need to kill the "reuse" branch of get_empty_super() to do that.
And that requires s_count already in place.

8. _Now_ we can get to real stuff.
	* kill_super() removes dying superblock from the super_blocks list.
	* when s_count drops to zero we free the superblock.

9. We are done with "reuse" branch of get_empty_super(). The rest (allocation
of new one) is renamed in alloc_super(). Insertion into the super_blocks
is moved into (the only) caller - read_super().

10. Now we can solve most of the problems with get_super()/umount().
get_super() does down_read(&s->s_umount (and drop_super() - up_read()).

>From that point it's more or less easy ride - we need to reorganize
get_sb_...() to have exclusion between mount() and get_super() callers,
but now we have everything we need for that.  I would rather submit that
part separately. All really evil stuff is done - in a sense it's the
nastiest point of sequence. Basically, the rest will consist of cleanups.

I've tried to carve the thing into edible chunks - if you find something
too large, please, tell. Patches themselves will go in followups to this
posting, numbered from 1 to 10. They are incremental to each other, starting
at 2.4.6-pre2.
							Cheers,
								Al


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (1/10)
  2001-06-11  5:32 [PATCHes] fs/super.c stuff Alexander Viro
@ 2001-06-11  5:33 ` Alexander Viro
  2001-06-11  5:33   ` [PATCH] fs/super.c stuff (2/10) Alexander Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:33 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2/fs/super.c S6-pre2-mnt_instances/fs/super.c
--- S6-pre2/fs/super.c	Fri Jun  8 18:29:03 2001
+++ S6-pre2-mnt_instances/fs/super.c	Sat Jun  9 19:18:31 2001
@@ -386,19 +386,20 @@
 	mnt->mnt_parent = mnt;
 
 	spin_lock(&dcache_lock);
-	list_add(&mnt->mnt_instances, &sb->s_mounts);
 	list_add(&mnt->mnt_list, vfsmntlist.prev);
 	spin_unlock(&dcache_lock);
+	atomic_inc(&sb->s_active);
 	if (sb->s_type->fs_flags & FS_SINGLE)
 		get_filesystem(sb->s_type);
 out:
 	return mnt;
 }
 
-static struct vfsmount *clone_mnt(struct vfsmount *old_mnt, struct dentry *root)
+static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)
 {
-	char *name = old_mnt->mnt_devname;
+	char *name = old->mnt_devname;
 	struct vfsmount *mnt = alloc_vfsmnt();
+	struct super_block *sb = old->mnt_sb;
 
 	if (!mnt)
 		goto out;
@@ -408,14 +409,12 @@
 		if (mnt->mnt_devname)
 			strcpy(mnt->mnt_devname, name);
 	}
-	mnt->mnt_sb = old_mnt->mnt_sb;
+	mnt->mnt_sb = sb;
 	mnt->mnt_root = dget(root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
 
-	spin_lock(&dcache_lock);
-	list_add(&mnt->mnt_instances, &old_mnt->mnt_instances);
-	spin_unlock(&dcache_lock);
+	atomic_inc(&sb->s_active);
 out:
 	return mnt;
 }
@@ -487,9 +486,6 @@
 	struct super_block *sb = mnt->mnt_sb;
 
 	dput(mnt->mnt_root);
-	spin_lock(&dcache_lock);
-	list_del(&mnt->mnt_instances);
-	spin_unlock(&dcache_lock);
 	if (mnt->mnt_devname)
 		kfree(mnt->mnt_devname);
 	kmem_cache_free(mnt_cache, mnt);
@@ -757,9 +753,9 @@
 		INIT_LIST_HEAD(&s->s_locked_inodes);
 		list_add (&s->s_list, super_blocks.prev);
 		INIT_LIST_HEAD(&s->s_files);
-		INIT_LIST_HEAD(&s->s_mounts);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
+		atomic_set(&s->s_active, 0);
 		sema_init(&s->s_vfs_rename_sem,1);
 		sema_init(&s->s_nfsd_free_path_sem,1);
 		sema_init(&s->s_dquot.dqio_sem, 1);
@@ -938,12 +934,9 @@
 	struct file_system_type *fs = sb->s_type;
 	struct super_operations *sop = sb->s_op;
 
-	spin_lock(&dcache_lock);
-	if (!list_empty(&sb->s_mounts)) {
-		spin_unlock(&dcache_lock);
+	atomic_dec(&sb->s_active);
+	if (atomic_read(&sb->s_active))
 		return;
-	}
-	spin_unlock(&dcache_lock);
 	down_write(&sb->s_umount);
 	lock_kernel();
 	sb->s_root = NULL;
@@ -1045,9 +1038,7 @@
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
-	spin_lock(&dcache_lock);
-	list_add(&mnt->mnt_instances, &sb->s_mounts);
-	spin_unlock(&dcache_lock);
+	atomic_inc(&sb->s_active);
 	type->kern_mnt = mnt;
 	return mnt;
 }
@@ -1092,7 +1083,7 @@
 
 	spin_lock(&dcache_lock);
 
-	if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
+	if (atomic_read(&sb->s_active) > 1) {
 		if (atomic_read(&mnt->mnt_count) > 2) {
 			spin_unlock(&dcache_lock);
 			return -EBUSY;
@@ -1324,9 +1315,7 @@
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
-	spin_lock(&dcache_lock);
-	list_add(&mnt->mnt_instances, &sb->s_mounts);
-	spin_unlock(&dcache_lock);
+	atomic_inc(&sb->s_active);
 
 	/* Something was mounted here while we slept */
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
diff -urN S6-pre2/include/linux/fs.h S6-pre2-mnt_instances/include/linux/fs.h
--- S6-pre2/include/linux/fs.h	Fri Jun  8 18:29:03 2001
+++ S6-pre2-mnt_instances/include/linux/fs.h	Sat Jun  9 19:18:31 2001
@@ -679,13 +679,13 @@
 	struct dentry		*s_root;
 	struct rw_semaphore	s_umount;
 	struct semaphore	s_lock;
+	atomic_t		s_active;
 
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_locked_inodes;/* inodes being synced */
 	struct list_head	s_files;
 
 	struct block_device	*s_bdev;
-	struct list_head	s_mounts;	/* vfsmount(s) of this one */
 	struct quota_mount_options s_dquot;	/* Diskquota specific options */
 
 	union {
diff -urN S6-pre2/include/linux/mount.h S6-pre2-mnt_instances/include/linux/mount.h
--- S6-pre2/include/linux/mount.h	Fri Jun  8 18:29:03 2001
+++ S6-pre2-mnt_instances/include/linux/mount.h	Sat Jun  9 19:18:31 2001
@@ -18,7 +18,6 @@
 	struct vfsmount *mnt_parent;	/* fs we are mounted on */
 	struct dentry *mnt_mountpoint;	/* dentry of mountpoint */
 	struct dentry *mnt_root;	/* root of the mounted tree */
-	struct list_head mnt_instances;	/* other vfsmounts of the same fs */
 	struct super_block *mnt_sb;	/* pointer to superblock */
 	struct list_head mnt_mounts;	/* list of children, anchored here */
 	struct list_head mnt_child;	/* and going through their mnt_child */



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (2/10)
  2001-06-11  5:33 ` [PATCH] fs/super.c stuff (1/10) Alexander Viro
@ 2001-06-11  5:33   ` Alexander Viro
  2001-06-11  5:34     ` [PATCH] fs/super.c stuff (3/10) Alexander Viro
  2001-06-11  5:34     ` Alexander Viro
  0 siblings, 2 replies; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:33 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-mnt_instances/fs/super.c S6-pre2-s_active/fs/super.c
--- S6-pre2-mnt_instances/fs/super.c	Sat Jun  9 19:18:31 2001
+++ S6-pre2-s_active/fs/super.c	Sun Jun 10 12:07:40 2001
@@ -388,7 +388,6 @@
 	spin_lock(&dcache_lock);
 	list_add(&mnt->mnt_list, vfsmntlist.prev);
 	spin_unlock(&dcache_lock);
-	atomic_inc(&sb->s_active);
 	if (sb->s_type->fs_flags & FS_SINGLE)
 		get_filesystem(sb->s_type);
 out:
@@ -740,6 +739,7 @@
 	     s  = sb_entry(s->s_list.next)) {
 		if (s->s_dev)
 			continue;
+		atomic_inc(&s->s_active);
 		return s;
 	}
 	/* Need a new one... */
@@ -755,7 +755,7 @@
 		INIT_LIST_HEAD(&s->s_files);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
-		atomic_set(&s->s_active, 0);
+		atomic_set(&s->s_active, 1);
 		sema_init(&s->s_vfs_rename_sem,1);
 		sema_init(&s->s_nfsd_free_path_sem,1);
 		sema_init(&s->s_dquot.dqio_sem, 1);
@@ -794,6 +794,7 @@
 	s->s_bdev = 0;
 	s->s_type = NULL;
 	unlock_super(s);
+	atomic_dec(&s->s_active);
 	return NULL;
 }
 
@@ -860,6 +861,7 @@
 		if (fs_type == sb->s_type &&
 		    ((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
 			path_release(&nd);
+			atomic_inc(&sb->s_active);
 			return sb;
 		}
 	} else {
@@ -923,6 +925,7 @@
 	if (!sb)
 		BUG();
 	do_remount_sb(sb, flags, data);
+	atomic_inc(&sb->s_active);
 	return sb;
 }
 
@@ -1038,7 +1041,6 @@
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
-	atomic_inc(&sb->s_active);
 	type->kern_mnt = mnt;
 	return mnt;
 }
@@ -1315,7 +1317,6 @@
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
-	atomic_inc(&sb->s_active);
 
 	/* Something was mounted here while we slept */
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
@@ -1573,6 +1574,7 @@
 	sb = get_super(ROOT_DEV);
 	if (sb) {
 		fs_type = sb->s_type;
+		atomic_inc(&sb->s_active);
 		goto mount_it;
 	}
 



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (3/10)
  2001-06-11  5:33   ` [PATCH] fs/super.c stuff (2/10) Alexander Viro
@ 2001-06-11  5:34     ` Alexander Viro
  2001-06-11  5:34     ` Alexander Viro
  1 sibling, 0 replies; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-s_active/fs/block_dev.c S6-pre2-fsync_no_super/fs/block_dev.c
--- S6-pre2-s_active/fs/block_dev.c	Fri Jun  8 18:29:02 2001
+++ S6-pre2-fsync_no_super/fs/block_dev.c	Sun Jun 10 12:13:03 2001
@@ -678,8 +678,10 @@
 	down(&bdev->bd_sem);
 	/* syncing will go here */
 	lock_kernel();
-	if (kind == BDEV_FILE || kind == BDEV_FS)
+	if (kind == BDEV_FILE)
 		fsync_dev(rdev);
+	else if (kind == BDEV_FS)
+		fsync_no_super(rdev);
 	if (atomic_dec_and_test(&bdev->bd_openers)) {
 		/* invalidating buffers will go here */
 		invalidate_buffers(rdev);
diff -urN S6-pre2-s_active/fs/buffer.c S6-pre2-fsync_no_super/fs/buffer.c
--- S6-pre2-s_active/fs/buffer.c	Fri Jun  8 18:29:03 2001
+++ S6-pre2-fsync_no_super/fs/buffer.c	Sun Jun 10 12:13:03 2001
@@ -318,6 +318,12 @@
 	return sync_buffers(dev, 1);
 }
 
+int fsync_no_super(kdev_t dev)
+{
+	sync_buffers(dev, 0);
+	return sync_buffers(dev, 1);
+}
+
 int fsync_dev(kdev_t dev)
 {
 	sync_buffers(dev, 0);
diff -urN S6-pre2-s_active/fs/super.c S6-pre2-fsync_no_super/fs/super.c
--- S6-pre2-s_active/fs/super.c	Sun Jun 10 12:07:40 2001
+++ S6-pre2-fsync_no_super/fs/super.c	Sun Jun 10 12:13:04 2001
@@ -971,12 +971,12 @@
 	sb->s_type = NULL;
 	unlock_super(sb);
 	unlock_kernel();
-	up_write(&sb->s_umount);
 	if (bdev) {
 		blkdev_put(bdev, BDEV_FS);
 		bdput(bdev);
 	} else
 		put_unnamed_dev(dev);
+	up_write(&sb->s_umount);
 }
 
 /*
diff -urN S6-pre2-s_active/include/linux/fs.h S6-pre2-fsync_no_super/include/linux/fs.h
--- S6-pre2-s_active/include/linux/fs.h	Sun Jun 10 11:58:01 2001
+++ S6-pre2-fsync_no_super/include/linux/fs.h	Sun Jun 10 12:13:04 2001
@@ -1122,6 +1122,7 @@
 extern void sync_dev(kdev_t);
 extern int fsync_dev(kdev_t);
 extern int fsync_super(struct super_block *);
+extern int fsync_no_super(kdev_t);
 extern void sync_inodes_sb(struct super_block *);
 extern int fsync_inode_buffers(struct inode *);
 extern int osync_inode_buffers(struct inode *);



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (3/10)
  2001-06-11  5:33   ` [PATCH] fs/super.c stuff (2/10) Alexander Viro
  2001-06-11  5:34     ` [PATCH] fs/super.c stuff (3/10) Alexander Viro
@ 2001-06-11  5:34     ` Alexander Viro
  2001-06-11  5:35       ` [PATCH] fs/super.c stuff (5/10) Alexander Viro
  2001-06-11  5:36       ` [PATCH] fs/super.c stuff (3/10) Alexander Viro
  1 sibling, 2 replies; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-fsync_no_super/include/linux/fs.h S6-pre2-put_super/include/linux/fs.h
--- S6-pre2-fsync_no_super/include/linux/fs.h	Sun Jun 10 18:36:27 2001
+++ S6-pre2-put_super/include/linux/fs.h	Sun Jun 10 18:39:04 2001
@@ -1320,7 +1320,6 @@
 
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
-extern void put_super(kdev_t);
 static inline int is_mounted(kdev_t dev)
 {
 	struct super_block *sb = get_super(dev);



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (5/10)
  2001-06-11  5:34     ` Alexander Viro
@ 2001-06-11  5:35       ` Alexander Viro
  2001-06-11  5:37         ` [PATCH] fs/super.c stuff (6/10) Alexander Viro
  2001-06-11  5:36       ` [PATCH] fs/super.c stuff (3/10) Alexander Viro
  1 sibling, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:35 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-put_super/fs/dquot.c S6-pre2-dquot/fs/dquot.c
--- S6-pre2-put_super/fs/dquot.c	Thu May 24 18:26:44 2001
+++ S6-pre2-dquot/fs/dquot.c	Sun Jun 10 18:46:54 2001
@@ -325,7 +325,7 @@
         memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
 }
 
-void invalidate_dquots(kdev_t dev, short type)
+static void invalidate_dquots(kdev_t dev, short type)
 {
 	struct dquot *dquot, *next;
 	int need_restart;
@@ -1388,7 +1388,7 @@
 }
 
 /* Function in inode.c - remove pointers to dquots in icache */
-extern void remove_dquot_ref(kdev_t, short);
+extern void remove_dquot_ref(struct super_block *, short);
 
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
@@ -1413,7 +1413,7 @@
 		reset_enable_flags(dqopt, cnt);
 
 		/* Note: these are blocking operations */
-		remove_dquot_ref(sb->s_dev, cnt);
+		remove_dquot_ref(sb, cnt);
 		invalidate_dquots(sb->s_dev, cnt);
 
 		/* Wait for any pending IO - remove me as soon as invalidate is more polite */
diff -urN S6-pre2-put_super/fs/inode.c S6-pre2-dquot/fs/inode.c
--- S6-pre2-put_super/fs/inode.c	Fri Jun  8 18:29:03 2001
+++ S6-pre2-dquot/fs/inode.c	Sun Jun 10 18:43:02 2001
@@ -1164,14 +1164,13 @@
 void put_dquot_list(struct list_head *);
 int remove_inode_dquot_ref(struct inode *, short, struct list_head *);
 
-void remove_dquot_ref(kdev_t dev, short type)
+void remove_dquot_ref(struct super_block *sb, short type)
 {
-	struct super_block *sb = get_super(dev);
 	struct inode *inode;
 	struct list_head *act_head;
 	LIST_HEAD(tofree_head);
 
-	if (!sb || !sb->dq_op)
+	if (!sb->dq_op)
 		return;	/* nothing to do */
 
 	/* We have to be protected against other CPUs */
diff -urN S6-pre2-put_super/include/linux/quotaops.h S6-pre2-dquot/include/linux/quotaops.h
--- S6-pre2-put_super/include/linux/quotaops.h	Sun Jun 10 13:15:27 2001
+++ S6-pre2-dquot/include/linux/quotaops.h	Sun Jun 10 18:46:33 2001
@@ -21,7 +21,6 @@
  */
 extern void dquot_initialize(struct inode *inode, short type);
 extern void dquot_drop(struct inode *inode);
-extern void invalidate_dquots(kdev_t dev, short type);
 extern int  quota_off(struct super_block *sb, short type);
 extern int  sync_dquots(kdev_t dev, short type);
 



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] fs/super.c stuff (3/10)
  2001-06-11  5:34     ` Alexander Viro
  2001-06-11  5:35       ` [PATCH] fs/super.c stuff (5/10) Alexander Viro
@ 2001-06-11  5:36       ` Alexander Viro
  1 sibling, 0 replies; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:36 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

	Grr... 4 of 10, that is. Sorry.

On Mon, 11 Jun 2001, Alexander Viro wrote:

> diff -urN S6-pre2-fsync_no_super/include/linux/fs.h S6-pre2-put_super/include/linux/fs.h
> --- S6-pre2-fsync_no_super/include/linux/fs.h	Sun Jun 10 18:36:27 2001
> +++ S6-pre2-put_super/include/linux/fs.h	Sun Jun 10 18:39:04 2001
> @@ -1320,7 +1320,6 @@
>  
>  extern struct file_system_type *get_fs_type(const char *name);
>  extern struct super_block *get_super(kdev_t);
> -extern void put_super(kdev_t);
>  static inline int is_mounted(kdev_t dev)
>  {
>  	struct super_block *sb = get_super(dev);
> 
> 
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] fs/super.c stuff (6/10)
  2001-06-11  5:35       ` [PATCH] fs/super.c stuff (5/10) Alexander Viro
@ 2001-06-11  5:37         ` Alexander Viro
  2001-06-11  5:37           ` [PATCH] fs/super.c stuff (7/10) Alexander Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:37 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-dquot/arch/parisc/hpux/sys_hpux.c S6-pre2-drop_super/arch/parisc/hpux/sys_hpux.c
--- S6-pre2-dquot/arch/parisc/hpux/sys_hpux.c	Fri Feb 16 20:46:44 2001
+++ S6-pre2-drop_super/arch/parisc/hpux/sys_hpux.c	Sun Jun 10 18:38:23 2001
@@ -109,9 +109,11 @@
 
 	lock_kernel();
 	s = get_super(to_kdev_t(dev));
+	unlock_kernel();
 	if (s == NULL)
 		goto out;
 	err = vfs_statfs(s, &sbuf);
+	drop_super(s);
 	if (err)
 		goto out;
 
@@ -124,7 +126,6 @@
 	/* Changed to hpux_ustat:  */
 	err = copy_to_user(ubuf,&tmp,sizeof(struct hpux_ustat)) ? -EFAULT : 0;
 out:
-	unlock_kernel();
 	return err;
 }
 
diff -urN S6-pre2-dquot/fs/dquot.c S6-pre2-drop_super/fs/dquot.c
--- S6-pre2-dquot/fs/dquot.c	Sun Jun 10 18:46:54 2001
+++ S6-pre2-drop_super/fs/dquot.c	Sun Jun 10 18:38:23 2001
@@ -1602,6 +1602,8 @@
 	if (sb && sb_has_quota_enabled(sb, type))
 		ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
 out:
+	if (sb)
+		drop_super(sb);
 	unlock_kernel();
 	return ret;
 }
diff -urN S6-pre2-dquot/fs/inode.c S6-pre2-drop_super/fs/inode.c
--- S6-pre2-dquot/fs/inode.c	Sun Jun 10 18:43:02 2001
+++ S6-pre2-drop_super/fs/inode.c	Sun Jun 10 18:38:23 2001
@@ -605,8 +605,10 @@
 		fsync_dev(dev);
 
 	res = 0;
-	if (sb)
+	if (sb) {
 		res = invalidate_inodes(sb);
+		drop_super(sb);
+	}
 	invalidate_buffers(dev);
 	return res;
 }
diff -urN S6-pre2-dquot/fs/super.c S6-pre2-drop_super/fs/super.c
--- S6-pre2-dquot/fs/super.c	Sun Jun 10 18:36:27 2001
+++ S6-pre2-drop_super/fs/super.c	Sun Jun 10 18:38:23 2001
@@ -491,7 +491,6 @@
 	kill_super(sb);
 }
 
-
 /* Use octal escapes, like mount does, for embedded spaces etc. */
 static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
 
@@ -640,6 +639,10 @@
 #undef MANGLE
 #undef FREEROOM
 }
+
+void drop_super(struct super_block *sb)
+{
+}
  
 /*
  * Note: check the dirty flag before waiting, so we don't
@@ -709,6 +712,7 @@
         if (s == NULL)
                 goto out;
 	err = vfs_statfs(s, &sbuf);
+	drop_super(s);
 	if (err)
 		goto out;
 
diff -urN S6-pre2-dquot/include/linux/fs.h S6-pre2-drop_super/include/linux/fs.h
--- S6-pre2-dquot/include/linux/fs.h	Sun Jun 10 18:39:04 2001
+++ S6-pre2-drop_super/include/linux/fs.h	Sun Jun 10 18:38:31 2001
@@ -1320,11 +1320,12 @@
 
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
+extern void drop_super(struct super_block *sb);
 static inline int is_mounted(kdev_t dev)
 {
 	struct super_block *sb = get_super(dev);
 	if (sb) {
-		/* drop_super(sb); will go here */
+		drop_super(sb);
 		return 1;
 	}
 	return 0;
diff -urN S6-pre2-dquot/kernel/ksyms.c S6-pre2-drop_super/kernel/ksyms.c
--- S6-pre2-dquot/kernel/ksyms.c	Fri Jun  8 18:29:03 2001
+++ S6-pre2-drop_super/kernel/ksyms.c	Sun Jun 10 18:38:23 2001
@@ -129,6 +129,7 @@
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_fs_type);
 EXPORT_SYMBOL(get_super);
+EXPORT_SYMBOL(drop_super);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(names_cachep);
 EXPORT_SYMBOL(fput);




^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (7/10)
  2001-06-11  5:37         ` [PATCH] fs/super.c stuff (6/10) Alexander Viro
@ 2001-06-11  5:37           ` Alexander Viro
  2001-06-11  5:38             ` [PATCH] fs/super.c stuff (8/10) Alexander Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:37 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-put_super/fs/inode.c S6-pre2-s_count/fs/inode.c
--- S6-pre2-put_super/fs/inode.c	Sun Jun 10 12:25:34 2001
+++ S6-pre2-s_count/fs/inode.c	Sun Jun 10 12:29:35 2001
@@ -339,30 +339,48 @@
 	spin_unlock(&inode_lock);
 }
 
+/*
+ * Note:
+ * We don't need to grab a reference to superblock here. If it has non-empty
+ * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
+ * past sync_inodes_sb() until both ->s_dirty and ->s_locked_inodes are
+ * empty. Since __sync_one() regains inode_lock before it finally moves
+ * inode from superblock lists we are OK.
+ */
+
 void sync_unlocked_inodes(void)
 {
-	struct super_block * sb = sb_entry(super_blocks.next);
+	struct super_block * sb;
+	spin_lock(&inode_lock);
+	spin_lock(&sb_lock);
+	sb = sb_entry(super_blocks.next);
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
 		if (!list_empty(&sb->s_dirty)) {
-			spin_lock(&inode_lock);
+			spin_unlock(&sb_lock);
 			sync_list(&sb->s_dirty);
-			spin_unlock(&inode_lock);
+			spin_lock(&sb_lock);
 		}
 	}
+	spin_unlock(&sb_lock);
+	spin_unlock(&inode_lock);
 }
 
 void sync_inodes(kdev_t dev)
 {
-	struct super_block * sb = sb_entry(super_blocks.next);
+	struct super_block * sb;
 
 	/*
 	 * Search the super_blocks array for the device(s) to sync.
 	 */
+	spin_lock(&sb_lock);
+	sb = sb_entry(super_blocks.next);
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
 		if (!sb->s_dev)
 			continue;
 		if (dev && sb->s_dev != dev)
 			continue;
+		sb->s_count++;
+		spin_unlock(&sb_lock);
 		down_read(&sb->s_umount);
 		if (sb->s_dev && (sb->s_dev == dev || !dev)) {
 			spin_lock(&inode_lock);
@@ -372,9 +390,12 @@
 			spin_unlock(&inode_lock);
 		}
 		up_read(&sb->s_umount);
+		spin_lock(&sb_lock);
+		sb->s_count--;
 		if (dev)
 			break;
 	}
+	spin_unlock(&sb_lock);
 }
 
 /*
@@ -382,13 +403,19 @@
  */
 static void try_to_sync_unused_inodes(void)
 {
-	struct super_block * sb = sb_entry(super_blocks.next);
+	struct super_block * sb;
+
+	spin_lock(&sb_lock);
+	sb = sb_entry(super_blocks.next);
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
 		if (!sb->s_dev)
 			continue;
+		spin_unlock(&sb_lock);
 		if (!try_to_sync_unused_list(&sb->s_dirty))
 			break;
+		spin_lock(&sb_lock);
 	}
+	spin_unlock(&sb_lock);
 }
 
 /**
diff -urN S6-pre2-put_super/fs/super.c S6-pre2-s_count/fs/super.c
--- S6-pre2-put_super/fs/super.c	Sun Jun 10 12:25:34 2001
+++ S6-pre2-s_count/fs/super.c	Sun Jun 10 12:35:54 2001
@@ -62,6 +62,7 @@
 int nr_super_blocks;
 int max_super_blocks = NR_SUPER;
 LIST_HEAD(super_blocks);
+spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Handling of filesystem drivers list.
@@ -640,8 +641,16 @@
 #undef FREEROOM
 }
 
+static inline void __put_super(struct super_block *sb)
+{
+	spin_lock(&sb_lock);
+	sb->s_count--;
+	spin_unlock(&sb_lock);
+}
+
 void drop_super(struct super_block *sb)
 {
+	__put_super(sb);
 }
  
 /*
@@ -653,6 +662,7 @@
 {
 	struct super_block * sb;
 
+	spin_lock(&sb_lock);
 	for (sb = sb_entry(super_blocks.next);
 	     sb != sb_entry(&super_blocks); 
 	     sb = sb_entry(sb->s_list.next)) {
@@ -662,12 +672,17 @@
 			continue;
 		if (!sb->s_dirt)
 			continue;
+		sb->s_count++;
+		spin_unlock(&sb_lock);
 		lock_super(sb);
 		if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev))
 			if (sb->s_op && sb->s_op->write_super)
 				sb->s_op->write_super(sb);
 		unlock_super(sb);
+		spin_lock(&sb_lock);
+		sb->s_count--;
 	}
+	spin_unlock(&sb_lock);
 }
 
 /**
@@ -685,17 +700,23 @@
 	if (!dev)
 		return NULL;
 restart:
+	spin_lock(&sb_lock);
 	s = sb_entry(super_blocks.next);
 	while (s != sb_entry(&super_blocks))
 		if (s->s_dev == dev) {
 			/* Yes, it sucks. As soon as we get refcounting... */
+			/* Almost there */
+			s->s_count++;
+			spin_unlock(&sb_lock);
 			lock_super(s);
 			unlock_super(s);
 			if (s->s_dev == dev)
 				return s;
+			drop_super(s);
 			goto restart;
 		} else
 			s = sb_entry(s->s_list.next);
+	spin_unlock(&sb_lock);
 	return NULL;
 }
 
@@ -738,14 +759,18 @@
 {
 	struct super_block *s;
 
+	spin_lock(&sb_lock);
 	for (s  = sb_entry(super_blocks.next);
 	     s != sb_entry(&super_blocks); 
 	     s  = sb_entry(s->s_list.next)) {
 		if (s->s_dev)
 			continue;
+		s->s_count++;
 		atomic_inc(&s->s_active);
+		spin_unlock(&sb_lock);
 		return s;
 	}
+	spin_unlock(&sb_lock);
 	/* Need a new one... */
 	if (nr_super_blocks >= max_super_blocks)
 		return NULL;
@@ -753,6 +778,7 @@
 	if (s) {
 		nr_super_blocks++;
 		memset(s, 0, sizeof(struct super_block));
+		spin_lock(&sb_lock);
 		INIT_LIST_HEAD(&s->s_dirty);
 		INIT_LIST_HEAD(&s->s_locked_inodes);
 		list_add (&s->s_list, super_blocks.prev);
@@ -760,10 +786,12 @@
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
 		atomic_set(&s->s_active, 1);
+		s->s_count = 1;
 		sema_init(&s->s_vfs_rename_sem,1);
 		sema_init(&s->s_nfsd_free_path_sem,1);
 		sema_init(&s->s_dquot.dqio_sem, 1);
 		sema_init(&s->s_dquot.dqoff_sem, 1);
+		spin_unlock(&sb_lock);
 	}
 	return s;
 }
@@ -799,6 +827,7 @@
 	s->s_type = NULL;
 	unlock_super(s);
 	atomic_dec(&s->s_active);
+	__put_super(s);
 	return NULL;
 }
 
@@ -864,10 +893,24 @@
 	if (sb) {
 		if (fs_type == sb->s_type &&
 		    ((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
-			path_release(&nd);
+/*
+ * We are heavily relying on mount_sem here. We _will_ get rid of that
+ * ugliness RSN (and then atomicity of ->s_active will play), but first
+ * we need to get rid of "reuse" branch of get_empty_super() and that
+ * requires reference counters. Chicken and egg problem, but fortunately
+ * we can use the fact that right now all accesses to ->s_active are
+ * under mount_sem.
+ */
+			if (atomic_read(&sb->s_active)) {
+				spin_lock(&sb_lock);
+				sb->s_count--;
+				spin_unlock(&sb_lock);
+			}
 			atomic_inc(&sb->s_active);
+			path_release(&nd);
 			return sb;
 		}
+		__put_super(sb);
 	} else {
 		mode_t mode = FMODE_READ; /* we always need it ;-) */
 		if (!(flags & MS_RDONLY))
@@ -941,8 +984,7 @@
 	struct file_system_type *fs = sb->s_type;
 	struct super_operations *sop = sb->s_op;
 
-	atomic_dec(&sb->s_active);
-	if (atomic_read(&sb->s_active))
+	if (!atomic_dec_and_test(&sb->s_active))
 		return;
 	down_write(&sb->s_umount);
 	lock_kernel();
@@ -981,6 +1023,7 @@
 	} else
 		put_unnamed_dev(dev);
 	up_write(&sb->s_umount);
+	__put_super(sb);
 }
 
 /*
@@ -1240,13 +1283,13 @@
 		return err;
 
 	err = -ENOMEM;
+	down(&mount_sem);
 	mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
 	if (mnt) {
-		down(&mount_sem);
 		err = graft_tree(mnt, nd);
-		up(&mount_sem);
 		mntput(mnt);
 	}
+	up(&mount_sem);
 	path_release(&old_nd);
 	return err;
 }
@@ -1577,6 +1620,7 @@
 	check_disk_change(ROOT_DEV);
 	sb = get_super(ROOT_DEV);
 	if (sb) {
+		/* FIXME */
 		fs_type = sb->s_type;
 		atomic_inc(&sb->s_active);
 		goto mount_it;
diff -urN S6-pre2-put_super/include/linux/fs.h S6-pre2-s_count/include/linux/fs.h
--- S6-pre2-put_super/include/linux/fs.h	Sun Jun 10 12:27:37 2001
+++ S6-pre2-s_count/include/linux/fs.h	Sun Jun 10 01:29:52 2001
@@ -662,6 +662,7 @@
 #include <linux/usbdev_fs_sb.h>
 
 extern struct list_head super_blocks;
+extern spinlock_t sb_lock;
 
 #define sb_entry(list)	list_entry((list), struct super_block, s_list)
 struct super_block {
@@ -679,6 +680,7 @@
 	struct dentry		*s_root;
 	struct rw_semaphore	s_umount;
 	struct semaphore	s_lock;
+	int			s_count;
 	atomic_t		s_active;
 
 	struct list_head	s_dirty;	/* dirty inodes */



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (8/10)
  2001-06-11  5:37           ` [PATCH] fs/super.c stuff (7/10) Alexander Viro
@ 2001-06-11  5:38             ` Alexander Viro
  2001-06-11  5:39               ` [PATCH] fs/super.c stuff (9/10) Alexander Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:38 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-s_count/fs/inode.c S6-pre2-freeing/fs/inode.c
--- S6-pre2-s_count/fs/inode.c	Sun Jun 10 12:45:04 2001
+++ S6-pre2-freeing/fs/inode.c	Sun Jun 10 12:45:47 2001
@@ -258,23 +258,6 @@
 		__sync_one(list_entry(tmp, struct inode, i_list), 0);
 }
 
-static inline int wait_on_dirty(struct list_head *head)
-{
-	struct list_head * tmp;
-	list_for_each(tmp, head) {
-		struct inode *inode = list_entry(tmp, struct inode, i_list);
-		if (!inode->i_state & I_DIRTY)
-			continue;
-		__iget(inode);
-		spin_unlock(&inode_lock);
-		__wait_on_inode(inode);
-		iput(inode);
-		spin_lock(&inode_lock);
-		return 1;
-	}
-	return 0;
-}
-
 static inline void wait_on_locked(struct list_head *head)
 {
 	struct list_head * tmp;
@@ -319,23 +302,13 @@
 	return 1;
 }
 
-/**
- *	sync_inodes
- *	@dev: device to sync the inodes from.
- *
- *	sync_inodes goes through the super block's dirty list, 
- *	writes them out, and puts them back on the normal list.
- */
-
-/*
- * caller holds exclusive lock on sb->s_umount
- */
- 
 void sync_inodes_sb(struct super_block *sb)
 {
 	spin_lock(&inode_lock);
-	sync_list(&sb->s_dirty);
-	wait_on_locked(&sb->s_locked_inodes);
+	while (!list_empty(&sb->s_dirty)||!list_empty(&sb->s_locked_inodes)) {
+		sync_list(&sb->s_dirty);
+		wait_on_locked(&sb->s_locked_inodes);
+	}
 	spin_unlock(&inode_lock);
 }
 
@@ -365,37 +338,75 @@
 	spin_unlock(&inode_lock);
 }
 
+/*
+ * Find a superblock with inodes that need to be synced
+ */
+
+static struct super_block *get_super_to_sync(void)
+{
+	struct list_head *p;
+restart:
+	spin_lock(&inode_lock);
+	spin_lock(&sb_lock);
+	list_for_each(p, &super_blocks) {
+		struct super_block *s = list_entry(p,struct super_block,s_list);
+		if (list_empty(&s->s_dirty) && list_empty(&s->s_locked_inodes))
+			continue;
+		s->s_count++;
+		spin_unlock(&sb_lock);
+		spin_unlock(&inode_lock);
+		down_read(&s->s_umount);
+		if (!s->s_root) {
+			up_read(&s->s_umount);
+			spin_lock(&sb_lock);
+			if (!--s->s_count)
+				kfree(s);
+			spin_unlock(&sb_lock);
+			goto restart;
+		}
+		return s;
+	}
+	spin_unlock(&sb_lock);
+	spin_unlock(&inode_lock);
+	return NULL;
+}
+
+/**
+ *	sync_inodes
+ *	@dev: device to sync the inodes from.
+ *
+ *	sync_inodes goes through the super block's dirty list, 
+ *	writes them out, and puts them back on the normal list.
+ */
+
 void sync_inodes(kdev_t dev)
 {
-	struct super_block * sb;
+	struct super_block * s;
 
 	/*
 	 * Search the super_blocks array for the device(s) to sync.
 	 */
-	spin_lock(&sb_lock);
-	sb = sb_entry(super_blocks.next);
-	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
-		if (!sb->s_dev)
-			continue;
-		if (dev && sb->s_dev != dev)
-			continue;
-		sb->s_count++;
-		spin_unlock(&sb_lock);
-		down_read(&sb->s_umount);
-		if (sb->s_dev && (sb->s_dev == dev || !dev)) {
-			spin_lock(&inode_lock);
-			do {
-				sync_list(&sb->s_dirty);
-			} while (wait_on_dirty(&sb->s_locked_inodes));
-			spin_unlock(&inode_lock);
+	if (dev) {
+		if ((s = get_super(dev)) != NULL) {
+			down_read(&s->s_umount);
+			if (s->s_root)
+				sync_inodes_sb(s);
+			up_read(&s->s_umount);
+			spin_lock(&sb_lock);
+			if (!--s->s_count)
+				kfree(s);
+			spin_unlock(&sb_lock);
+		}
+	} else {
+		while ((s = get_super_to_sync()) != NULL) {
+			sync_inodes_sb(s);
+			up_read(&s->s_umount);
+			spin_lock(&sb_lock);
+			if (!--s->s_count)
+				kfree(s);
+			spin_unlock(&sb_lock);
 		}
-		up_read(&sb->s_umount);
-		spin_lock(&sb_lock);
-		sb->s_count--;
-		if (dev)
-			break;
 	}
-	spin_unlock(&sb_lock);
 }
 
 /*
diff -urN S6-pre2-s_count/fs/super.c S6-pre2-freeing/fs/super.c
--- S6-pre2-s_count/fs/super.c	Sun Jun 10 12:45:04 2001
+++ S6-pre2-freeing/fs/super.c	Sun Jun 10 12:45:47 2001
@@ -644,7 +644,8 @@
 static inline void __put_super(struct super_block *sb)
 {
 	spin_lock(&sb_lock);
-	sb->s_count--;
+	if (!--sb->s_count)
+		kfree(sb);
 	spin_unlock(&sb_lock);
 }
 
@@ -652,6 +653,21 @@
 {
 	__put_super(sb);
 }
+
+static void put_super(struct super_block *sb)
+{
+	up_write(&sb->s_umount);
+	__put_super(sb);
+}
+
+static inline void write_super(struct super_block *sb)
+{
+	lock_super(sb);
+	if (sb->s_root && sb->s_dirt)
+		if (sb->s_op && sb->s_op->write_super)
+			sb->s_op->write_super(sb);
+	unlock_super(sb);
+}
  
 /*
  * Note: check the dirty flag before waiting, so we don't
@@ -662,26 +678,30 @@
 {
 	struct super_block * sb;
 
-	spin_lock(&sb_lock);
-	for (sb = sb_entry(super_blocks.next);
-	     sb != sb_entry(&super_blocks); 
-	     sb = sb_entry(sb->s_list.next)) {
-		if (!sb->s_dev)
-			continue;
-		if (dev && sb->s_dev != dev)
-			continue;
-		if (!sb->s_dirt)
-			continue;
-		sb->s_count++;
-		spin_unlock(&sb_lock);
-		lock_super(sb);
-		if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev))
-			if (sb->s_op && sb->s_op->write_super)
-				sb->s_op->write_super(sb);
-		unlock_super(sb);
-		spin_lock(&sb_lock);
-		sb->s_count--;
+	if (dev) {
+		sb = get_super(dev);
+		if (sb) {
+			if (sb->s_dirt)
+				write_super(sb);
+			up_read(&sb->s_umount);
+			__put_super(sb);
+		}
+		return;
 	}
+restart:
+	spin_lock(&sb_lock);
+	sb = sb_entry(super_blocks.next);
+	while (sb != sb_entry(&super_blocks))
+		if (sb->s_dirt) {
+			sb->s_count++;
+			spin_unlock(&sb_lock);
+			down_read(&sb->s_umount);
+			write_super(sb);
+			up_read(&sb->s_umount);
+			__put_super(sb);
+			goto restart;
+		} else
+			sb = sb_entry(sb->s_list.next);
 	spin_unlock(&sb_lock);
 }
 
@@ -1022,8 +1042,10 @@
 		bdput(bdev);
 	} else
 		put_unnamed_dev(dev);
-	up_write(&sb->s_umount);
-	__put_super(sb);
+	spin_lock(&sb_lock);
+	list_del(&sb->s_list);
+	spin_unlock(&sb_lock);
+	put_super(sb);
 }
 
 /*



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (9/10)
  2001-06-11  5:38             ` [PATCH] fs/super.c stuff (8/10) Alexander Viro
@ 2001-06-11  5:39               ` Alexander Viro
  2001-06-11  5:40                 ` [PATCH] fs/super.c stuff (10/10) Alexander Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:39 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-freeing/fs/super.c S6-pre2-current/fs/super.c
--- S6-pre2-freeing/fs/super.c	Sun Jun 10 12:45:47 2001
+++ S6-pre2-current/fs/super.c	Sun Jun 10 12:53:15 2001
@@ -59,8 +59,6 @@
 /* this is initialized in init/main.c */
 kdev_t ROOT_DEV;
 
-int nr_super_blocks;
-int max_super_blocks = NR_SUPER;
 LIST_HEAD(super_blocks);
 spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
 
@@ -775,43 +773,23 @@
  *	the request.
  */
  
-static struct super_block *get_empty_super(void)
+static struct super_block *alloc_super(void)
 {
-	struct super_block *s;
-
-	spin_lock(&sb_lock);
-	for (s  = sb_entry(super_blocks.next);
-	     s != sb_entry(&super_blocks); 
-	     s  = sb_entry(s->s_list.next)) {
-		if (s->s_dev)
-			continue;
-		s->s_count++;
-		atomic_inc(&s->s_active);
-		spin_unlock(&sb_lock);
-		return s;
-	}
-	spin_unlock(&sb_lock);
-	/* Need a new one... */
-	if (nr_super_blocks >= max_super_blocks)
-		return NULL;
-	s = kmalloc(sizeof(struct super_block),  GFP_USER);
+	struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
 	if (s) {
-		nr_super_blocks++;
 		memset(s, 0, sizeof(struct super_block));
-		spin_lock(&sb_lock);
 		INIT_LIST_HEAD(&s->s_dirty);
 		INIT_LIST_HEAD(&s->s_locked_inodes);
-		list_add (&s->s_list, super_blocks.prev);
 		INIT_LIST_HEAD(&s->s_files);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
-		atomic_set(&s->s_active, 1);
 		s->s_count = 1;
+		atomic_set(&s->s_active, 1);
 		sema_init(&s->s_vfs_rename_sem,1);
 		sema_init(&s->s_nfsd_free_path_sem,1);
 		sema_init(&s->s_dquot.dqio_sem, 1);
 		sema_init(&s->s_dquot.dqoff_sem, 1);
-		spin_unlock(&sb_lock);
+		s->s_maxbytes = MAX_NON_LFS;
 	}
 	return s;
 }
@@ -821,16 +799,16 @@
 				       void *data, int silent)
 {
 	struct super_block * s;
-	s = get_empty_super();
+	s = alloc_super();
 	if (!s)
 		goto out;
 	s->s_dev = dev;
 	s->s_bdev = bdev;
 	s->s_flags = flags;
-	s->s_dirt = 0;
 	s->s_type = type;
-	s->s_dquot.flags = 0;
-	s->s_maxbytes = MAX_NON_LFS;
+	spin_lock(&sb_lock);
+	list_add (&s->s_list, super_blocks.prev);
+	spin_unlock(&sb_lock);
 	lock_super(s);
 	if (!type->read_super(s, data, silent))
 		goto out_fail;
@@ -991,8 +969,8 @@
 	sb = fs_type->kern_mnt->mnt_sb;
 	if (!sb)
 		BUG();
-	do_remount_sb(sb, flags, data);
 	atomic_inc(&sb->s_active);
+	do_remount_sb(sb, flags, data);
 	return sb;
 }
 
diff -urN S6-pre2-freeing/include/linux/fs.h S6-pre2-current/include/linux/fs.h
--- S6-pre2-freeing/include/linux/fs.h	Sun Jun 10 12:45:04 2001
+++ S6-pre2-current/include/linux/fs.h	Sun Jun 10 06:10:13 2001
@@ -61,7 +61,6 @@
 };
 extern struct inodes_stat_t inodes_stat;
 
-extern int max_super_blocks, nr_super_blocks;
 extern int leases_enable, dir_notify_enable, lease_break_time;
 
 #define NR_FILE  8192	/* this can well be larger on a larger system */
diff -urN S6-pre2-freeing/kernel/sysctl.c S6-pre2-current/kernel/sysctl.c
--- S6-pre2-freeing/kernel/sysctl.c	Sat Apr 14 21:41:29 2001
+++ S6-pre2-current/kernel/sysctl.c	Sun Jun 10 06:09:56 2001
@@ -286,10 +286,6 @@
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-	{FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
-	 0444, NULL, &proc_dointvec},
-	{FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
-	 0644, NULL, &proc_dointvec},
 	{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] fs/super.c stuff (10/10)
  2001-06-11  5:39               ` [PATCH] fs/super.c stuff (9/10) Alexander Viro
@ 2001-06-11  5:40                 ` Alexander Viro
  0 siblings, 0 replies; 12+ messages in thread
From: Alexander Viro @ 2001-06-11  5:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

diff -urN S6-pre2-alloc_super/fs/inode.c S6-pre2-current/fs/inode.c
--- S6-pre2-alloc_super/fs/inode.c	Sun Jun 10 19:09:35 2001
+++ S6-pre2-current/fs/inode.c	Sun Jun 10 19:26:27 2001
@@ -357,11 +357,7 @@
 		spin_unlock(&inode_lock);
 		down_read(&s->s_umount);
 		if (!s->s_root) {
-			up_read(&s->s_umount);
-			spin_lock(&sb_lock);
-			if (!--s->s_count)
-				kfree(s);
-			spin_unlock(&sb_lock);
+			drop_super(s);
 			goto restart;
 		}
 		return s;
@@ -388,23 +384,13 @@
 	 */
 	if (dev) {
 		if ((s = get_super(dev)) != NULL) {
-			down_read(&s->s_umount);
-			if (s->s_root)
-				sync_inodes_sb(s);
-			up_read(&s->s_umount);
-			spin_lock(&sb_lock);
-			if (!--s->s_count)
-				kfree(s);
-			spin_unlock(&sb_lock);
+			sync_inodes_sb(s);
+			drop_super(s);
 		}
 	} else {
 		while ((s = get_super_to_sync()) != NULL) {
 			sync_inodes_sb(s);
-			up_read(&s->s_umount);
-			spin_lock(&sb_lock);
-			if (!--s->s_count)
-				kfree(s);
-			spin_unlock(&sb_lock);
+			drop_super(s);
 		}
 	}
 }
@@ -636,13 +622,14 @@
  
 int invalidate_device(kdev_t dev, int do_sync)
 {
-	struct super_block *sb = get_super(dev);
+	struct super_block *sb;
 	int res;
 
 	if (do_sync)
 		fsync_dev(dev);
 
 	res = 0;
+	sb = get_super(dev);
 	if (sb) {
 		res = invalidate_inodes(sb);
 		drop_super(sb);
diff -urN S6-pre2-alloc_super/fs/super.c S6-pre2-current/fs/super.c
--- S6-pre2-alloc_super/fs/super.c	Sun Jun 10 19:09:39 2001
+++ S6-pre2-current/fs/super.c	Sun Jun 10 19:36:51 2001
@@ -647,8 +647,23 @@
 	spin_unlock(&sb_lock);
 }
 
+static inline struct super_block * find_super(kdev_t dev)
+{
+	struct list_head *p;
+
+	list_for_each(p, &super_blocks) {
+		struct super_block * s = sb_entry(p);
+		if (s->s_dev == dev) {
+			s->s_count++;
+			return s;
+		}
+	}
+	return NULL;
+}
+
 void drop_super(struct super_block *sb)
 {
+	up_read(&sb->s_umount);
 	__put_super(sb);
 }
 
@@ -681,8 +696,7 @@
 		if (sb) {
 			if (sb->s_dirt)
 				write_super(sb);
-			up_read(&sb->s_umount);
-			__put_super(sb);
+			drop_super(sb);
 		}
 		return;
 	}
@@ -695,8 +709,7 @@
 			spin_unlock(&sb_lock);
 			down_read(&sb->s_umount);
 			write_super(sb);
-			up_read(&sb->s_umount);
-			__put_super(sb);
+			drop_super(sb);
 			goto restart;
 		} else
 			sb = sb_entry(sb->s_list.next);
@@ -719,21 +732,19 @@
 		return NULL;
 restart:
 	spin_lock(&sb_lock);
-	s = sb_entry(super_blocks.next);
-	while (s != sb_entry(&super_blocks))
-		if (s->s_dev == dev) {
-			/* Yes, it sucks. As soon as we get refcounting... */
-			/* Almost there */
-			s->s_count++;
-			spin_unlock(&sb_lock);
-			lock_super(s);
-			unlock_super(s);
-			if (s->s_dev == dev)
-				return s;
-			drop_super(s);
-			goto restart;
-		} else
-			s = sb_entry(s->s_list.next);
+	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;
+		drop_super(s);
+		goto restart;
+	}
 	spin_unlock(&sb_lock);
 	return NULL;
 }
@@ -905,10 +916,11 @@
 				spin_unlock(&sb_lock);
 			}
 			atomic_inc(&sb->s_active);
+			up_read(&sb->s_umount);
 			path_release(&nd);
 			return sb;
 		}
-		__put_super(sb);
+		drop_super(sb);
 	} else {
 		mode_t mode = FMODE_READ; /* we always need it ;-) */
 		if (!(flags & MS_RDONLY))
@@ -1623,6 +1635,7 @@
 		/* FIXME */
 		fs_type = sb->s_type;
 		atomic_inc(&sb->s_active);
+		up_read(&sb->s_umount);
 		goto mount_it;
 	}
 



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2001-06-11  5:40 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-06-11  5:32 [PATCHes] fs/super.c stuff Alexander Viro
2001-06-11  5:33 ` [PATCH] fs/super.c stuff (1/10) Alexander Viro
2001-06-11  5:33   ` [PATCH] fs/super.c stuff (2/10) Alexander Viro
2001-06-11  5:34     ` [PATCH] fs/super.c stuff (3/10) Alexander Viro
2001-06-11  5:34     ` Alexander Viro
2001-06-11  5:35       ` [PATCH] fs/super.c stuff (5/10) Alexander Viro
2001-06-11  5:37         ` [PATCH] fs/super.c stuff (6/10) Alexander Viro
2001-06-11  5:37           ` [PATCH] fs/super.c stuff (7/10) Alexander Viro
2001-06-11  5:38             ` [PATCH] fs/super.c stuff (8/10) Alexander Viro
2001-06-11  5:39               ` [PATCH] fs/super.c stuff (9/10) Alexander Viro
2001-06-11  5:40                 ` [PATCH] fs/super.c stuff (10/10) Alexander Viro
2001-06-11  5:36       ` [PATCH] fs/super.c stuff (3/10) Alexander Viro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).