On Fri, 29 Dec 2000, Linus Torvalds wrote:

> > Oblock_super(): what the hell is wait_on_super() doing in fsync_file()?
> > It gives absolutely no warranties - ->write_super() can easily block, so
> > it looks very odd.
> 
> A lot of the superblock locking has been odd. It should probably be a
> lock_super() + unlock_super(). At least that's what sync_supers() does.

Yeah, that's what I've done, but I'm less than sure that we need anything
of that kind in the first place...

Anyway, under the "it works here" category: current state of sane-s_lock
patch. It will need further cleanup in fs/super.c, but IMO the current
form is already better than code in tree. Comments are more than welcome.

One note on the patch: sb->s_count is amount of extra references to superblock
(== not coming from vfsmounts) + 1 if there is a vfsmount over that superblock.
I.e. same scheme as we use for mm_struct. get_super() bumps the refcount,
put_super() decrements it and frees the superblock if counter hits zero.
add_vfsmnt() bumps refcount if we are adding the first vfsmount.
remove_vfsmnt() bumps refcount _unless_ we are removing the last vfsmount.
I.e. remove_vfsmnt() + put_super() always does the right thing.

List of superblocks contains only "active" ones. kill_super() takes the
superblock out of the list. get_empty_super() became simpler - it doesn't
bother searching the list for "reusable" ones. List is still BKL-protected;
I'll fix that.

We got _two_ sempaphores - one for get_super()/umount() synchronization
(->s_umount) and another for lock_super()/unlock_super() (->s_lock).
I would expect the latter to go into the per-fs part - all synchronization
that is interesting from VFS point of view is done by ->s_umount. The
reason why I've kept s_lock at all is simple - I don't want to mix
changes in fs-private synchronization with the fs-independent stuff.

Patch is against -pre6 and it seems to working here. Comments (and help
in testing) are welcome.

Peter, if you could remind me the uses of get_empty_super() and friends
in your code I would be very grateful - I seriously suspect that we
could use better interface in that area.
                                                        Cheers,
                                                                Al
Patch follows:

diff -urN rc13-pre6/arch/parisc/hpux/sys_hpux.c 
rc13-pre6-s_lock/arch/parisc/hpux/sys_hpux.c
--- rc13-pre6/arch/parisc/hpux/sys_hpux.c       Tue Dec 12 02:10:00 2000
+++ rc13-pre6-s_lock/arch/parisc/hpux/sys_hpux.c        Sat Dec 30 09:17:25 2000
@@ -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);
+       put_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 rc13-pre6/arch/sparc/kernel/sys_sunos.c 
rc13-pre6-s_lock/arch/sparc/kernel/sys_sunos.c
--- rc13-pre6/arch/sparc/kernel/sys_sunos.c     Sun Aug 13 16:56:28 2000
+++ rc13-pre6-s_lock/arch/sparc/kernel/sys_sunos.c      Sat Dec 30 09:17:25 2000
@@ -620,8 +620,6 @@
 };
 
 
-extern dev_t get_unnamed_dev(void);
-extern void put_unnamed_dev(dev_t);
 extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
 extern asmlinkage int sys_socket(int family, int type, int protocol);
 extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
diff -urN rc13-pre6/arch/sparc64/kernel/sys_sunos32.c 
rc13-pre6-s_lock/arch/sparc64/kernel/sys_sunos32.c
--- rc13-pre6/arch/sparc64/kernel/sys_sunos32.c Tue Dec 12 02:10:04 2000
+++ rc13-pre6-s_lock/arch/sparc64/kernel/sys_sunos32.c  Sat Dec 30 09:17:25 2000
@@ -580,8 +580,6 @@
        char       *netname;   /* server's netname */
 };
 
-extern dev_t get_unnamed_dev(void);
-extern void put_unnamed_dev(dev_t);
 extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
 extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
 extern asmlinkage int sys_socket(int family, int type, int protocol);
diff -urN rc13-pre6/drivers/acorn/block/mfmhd.c 
rc13-pre6-s_lock/drivers/acorn/block/mfmhd.c
--- rc13-pre6/drivers/acorn/block/mfmhd.c       Wed Nov 29 19:28:26 2000
+++ rc13-pre6-s_lock/drivers/acorn/block/mfmhd.c        Sat Dec 30 09:17:26 2000
@@ -1486,13 +1486,8 @@
        for (i = maxp - 1; i >= 0; i--) {
                int minor = start + i;
                kdev_t devi = MKDEV(MAJOR_NR, minor);
-               struct super_block *sb = get_super(devi);
-
-               sync_dev (devi);
-               if (sb)
-                       invalidate_inodes (sb);
-               invalidate_buffers (devi);
 
+               invalidate_dev(devi, 1);
                mfm_gendisk.part[minor].start_sect = 0;
                mfm_gendisk.part[minor].nr_sects = 0;
        }
diff -urN rc13-pre6/drivers/block/DAC960.c rc13-pre6-s_lock/drivers/block/DAC960.c
--- rc13-pre6/drivers/block/DAC960.c    Tue Dec 12 02:10:05 2000
+++ rc13-pre6-s_lock/drivers/block/DAC960.c     Sat Dec 30 09:17:26 2000
@@ -4990,16 +4990,12 @@
                                                      PartitionNumber);
          int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
                                               PartitionNumber);
-         SuperBlock_T *SuperBlock = get_super(Device);
          if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
            continue;
          /*
            Flush all changes and invalidate buffered state.
          */
-         sync_dev(Device);
-         if (SuperBlock != NULL)
-           invalidate_inodes(SuperBlock);
-         invalidate_buffers(Device);
+         invalidate_dev(Device, 1);
          /*
            Clear existing partition sizes.
          */
diff -urN rc13-pre6/drivers/block/acsi.c rc13-pre6-s_lock/drivers/block/acsi.c
--- rc13-pre6/drivers/block/acsi.c      Tue Dec 12 02:10:05 2000
+++ rc13-pre6-s_lock/drivers/block/acsi.c       Sat Dec 30 09:17:26 2000
@@ -1887,12 +1887,7 @@
        for( i = max_p - 1; i >= 0 ; i-- ) {
                if (gdev->part[start + i].nr_sects != 0) {
                        kdev_t devp = MKDEV(MAJOR_NR, start + i);
-                       struct super_block *sb = get_super(devp);
-
-                       fsync_dev(devp);
-                       if (sb)
-                               invalidate_inodes(sb);
-                       invalidate_buffers(devp);
+                       invalidate_dev(devp, 2);
                        gdev->part[start + i].nr_sects = 0;
                }
                gdev->part[start+i].start_sect = 0;
diff -urN rc13-pre6/drivers/block/amiflop.c rc13-pre6-s_lock/drivers/block/amiflop.c
--- rc13-pre6/drivers/block/amiflop.c   Wed Nov 29 19:28:35 2000
+++ rc13-pre6-s_lock/drivers/block/amiflop.c    Sat Dec 30 09:17:26 2000
@@ -1490,7 +1490,6 @@
 {
        int drive = inode->i_rdev & 3;
        static struct floppy_struct getprm;
-       struct super_block * sb;
 
        switch(cmd){
        case HDIO_GETGEO:
@@ -1540,10 +1539,7 @@
                break;
        case FDFMTEND:
                floppy_off(drive);
-               sb = get_super(inode->i_rdev);
-               if (sb)
-                       invalidate_inodes(sb);
-               invalidate_buffers(inode->i_rdev);
+               invalidate_dev(inode->i_rdev, 0);
                break;
        case FDGETPRM:
                memset((void *)&getprm, 0, sizeof (getprm));
@@ -1677,9 +1673,6 @@
 
 static int floppy_release(struct inode * inode, struct file * filp)
 {
-#ifdef DEBUG
-       struct super_block * sb;
-#endif
        int drive = MINOR(inode->i_rdev) & 3;
 
        if (unit[drive].dirty == 1) {
diff -urN rc13-pre6/drivers/block/blkpg.c rc13-pre6-s_lock/drivers/block/blkpg.c
--- rc13-pre6/drivers/block/blkpg.c     Mon Mar 20 01:36:47 2000
+++ rc13-pre6-s_lock/drivers/block/blkpg.c      Sat Dec 30 09:17:26 2000
@@ -157,8 +157,7 @@
 
        /* partition in use? Incomplete check for now. */
        devp = MKDEV(MAJOR(dev), minor);
-       if (get_super(devp) ||          /* mounted? */
-           is_swap_partition(devp))
+       if (is_mounted(devp) || is_swap_partition(devp))
                return -EBUSY;
 
        /* all seems OK */
diff -urN rc13-pre6/drivers/block/cciss.c rc13-pre6-s_lock/drivers/block/cciss.c
--- rc13-pre6/drivers/block/cciss.c     Wed Nov 29 21:36:25 2000
+++ rc13-pre6-s_lock/drivers/block/cciss.c      Sat Dec 30 09:17:26 2000
@@ -707,10 +707,7 @@
         for(i=max_p; i>=0; i--) {
                 int minor = start+i;
                 kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
-                struct super_block *sb = get_super(devi);
-                sync_dev(devi);
-                if (sb) invalidate_inodes(sb);
-                invalidate_buffers(devi);
+               invalidate_dev(devi, 1);
                 gdev->part[minor].start_sect = 0;
                 gdev->part[minor].nr_sects = 0;
 
diff -urN rc13-pre6/drivers/block/cpqarray.c rc13-pre6-s_lock/drivers/block/cpqarray.c
--- rc13-pre6/drivers/block/cpqarray.c  Wed Nov 29 21:42:57 2000
+++ rc13-pre6-s_lock/drivers/block/cpqarray.c   Sat Dec 30 09:17:26 2000
@@ -1571,10 +1571,7 @@
        for(i=max_p; i>=0; i--) {
                int minor = start+i;
                kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
-               struct super_block *sb = get_super(devi);
-               sync_dev(devi);
-               if (sb) invalidate_inodes(sb);
-               invalidate_buffers(devi);
+               invalidate_dev(devi, 1);
                gdev->part[minor].start_sect = 0;       
                gdev->part[minor].nr_sects = 0; 
 
diff -urN rc13-pre6/drivers/block/paride/pd.c 
rc13-pre6-s_lock/drivers/block/paride/pd.c
--- rc13-pre6/drivers/block/paride/pd.c Tue Jul 25 09:23:16 2000
+++ rc13-pre6-s_lock/drivers/block/paride/pd.c  Sat Dec 30 09:17:26 2000
@@ -593,8 +593,6 @@
         long flags;
         kdev_t devp;
 
-       struct super_block *sb;
-
         unit = DEVICE_NR(dev);
         if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
 
@@ -610,12 +608,7 @@
         for (p=(PD_PARTNS-1);p>=0;p--) {
                minor = p + unit*PD_PARTNS;
                 devp = MKDEV(MAJOR_NR, minor);
-                fsync_dev(devp);
-
-                sb = get_super(devp);
-                if (sb) invalidate_inodes(sb);
-
-                invalidate_buffers(devp);
+               invalidate_dev(devp, 2);
                 pd_hd[minor].start_sect = 0;
                 pd_hd[minor].nr_sects = 0;
         }
diff -urN rc13-pre6/drivers/block/ps2esdi.c rc13-pre6-s_lock/drivers/block/ps2esdi.c
--- rc13-pre6/drivers/block/ps2esdi.c   Mon Jul 31 16:33:53 2000
+++ rc13-pre6-s_lock/drivers/block/ps2esdi.c    Sat Dec 30 09:17:26 2000
@@ -1180,12 +1180,7 @@
             partition >= 0; partition--) {
                int minor = (start | partition);
                kdev_t devp = MKDEV(MAJOR_NR, minor);
-               struct super_block * sb = get_super(devp);
-               
-               sync_dev(devp);
-               if (sb)
-                       invalidate_inodes(sb);
-               invalidate_buffers(devp);
+               invalidate_dev(devp, 1);
                ps2esdi_gendisk.part[start + partition].start_sect = 0;
                ps2esdi_gendisk.part[start + partition].nr_sects = 0;
        }
diff -urN rc13-pre6/drivers/block/xd.c rc13-pre6-s_lock/drivers/block/xd.c
--- rc13-pre6/drivers/block/xd.c        Wed Nov 29 21:36:26 2000
+++ rc13-pre6-s_lock/drivers/block/xd.c Sat Dec 30 09:17:26 2000
@@ -394,12 +394,7 @@
        for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
                int minor = (start | partition);
                kdev_t devp = MKDEV(MAJOR_NR, minor);
-               struct super_block * sb = get_super(devp);
-               
-               sync_dev(devp);
-               if (sb)
-                       invalidate_inodes(sb);
-               invalidate_buffers(devp);
+               invalidate_dev(devp, 1);
                xd_gendisk.part[minor].start_sect = 0;
                xd_gendisk.part[minor].nr_sects = 0;
        };
diff -urN rc13-pre6/drivers/char/raw.c rc13-pre6-s_lock/drivers/char/raw.c
--- rc13-pre6/drivers/char/raw.c        Wed Nov 29 19:28:41 2000
+++ rc13-pre6-s_lock/drivers/char/raw.c Sat Dec 30 09:17:26 2000
@@ -103,7 +103,7 @@
         */
        
        sector_size = 512;
-       if (get_super(rdev) != NULL) {
+       if (is_mounted(rdev)) {
                if (blksize_size[MAJOR(rdev)])
                        sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)];
        } else {
diff -urN rc13-pre6/drivers/i2o/i2o_block.c rc13-pre6-s_lock/drivers/i2o/i2o_block.c
--- rc13-pre6/drivers/i2o/i2o_block.c   Wed Nov 29 21:43:05 2000
+++ rc13-pre6-s_lock/drivers/i2o/i2o_block.c    Sat Dec 30 09:17:27 2000
@@ -900,12 +900,7 @@
        {
                int m = minor+i;
                kdev_t d = MKDEV(MAJOR_NR, m);
-               struct super_block *sb = get_super(d);
-               
-               sync_dev(d);
-               if(sb)
-                       invalidate_inodes(sb);
-               invalidate_buffers(d);
+               invalidate_dev(d, 1);
                i2ob_gendisk.part[m].start_sect = 0;
                i2ob_gendisk.part[m].nr_sects = 0;
        }
diff -urN rc13-pre6/drivers/ide/hd.c rc13-pre6-s_lock/drivers/ide/hd.c
--- rc13-pre6/drivers/ide/hd.c  Wed Nov 29 21:43:06 2000
+++ rc13-pre6-s_lock/drivers/ide/hd.c   Sat Dec 30 09:17:27 2000
@@ -881,12 +881,7 @@
        for (i=max_p - 1; i >=0 ; i--) {
                int minor = start + i;
                kdev_t devi = MKDEV(MAJOR_NR, minor);
-               struct super_block *sb = get_super(devi); 
-
-               sync_dev(devi);
-               if (sb)
-                       invalidate_inodes(sb);
-               invalidate_buffers(devi);
+               invalidate_dev(devi, 1);
                gdev->part[minor].start_sect = 0;
                gdev->part[minor].nr_sects = 0;
        }
diff -urN rc13-pre6/drivers/ide/ide.c rc13-pre6-s_lock/drivers/ide/ide.c
--- rc13-pre6/drivers/ide/ide.c Tue Dec 12 02:10:10 2000
+++ rc13-pre6-s_lock/drivers/ide/ide.c  Sat Dec 30 09:17:27 2000
@@ -1761,11 +1761,7 @@
        for (p = 0; p < (1<<PARTN_BITS); ++p) {
                if (drive->part[p].nr_sects > 0) {
                        kdev_t devp = MKDEV(major, minor+p);
-                       struct super_block * sb = get_super(devp);
-                       fsync_dev          (devp);
-                       if (sb)
-                               invalidate_inodes(sb);
-                       invalidate_buffers (devp);
+                       invalidate_dev(devp, 2);
                        set_blocksize(devp, 1024);
                }
                drive->part[p].start_sect = 0;
@@ -1982,9 +1978,7 @@
                for (p = 0; p < (1<<PARTN_BITS); ++p) {
                        if (drive->part[p].nr_sects > 0) {
                                kdev_t devp = MKDEV(hwif->major, minor+p);
-                               struct super_block * sb = get_super(devp);
-                               if (sb) invalidate_inodes(sb);
-                               invalidate_buffers (devp);
+                               invalidate_dev(devp, 0);
                        }
                }
 #ifdef CONFIG_PROC_FS
diff -urN rc13-pre6/drivers/md/md.c rc13-pre6-s_lock/drivers/md/md.c
--- rc13-pre6/drivers/md/md.c   Tue Dec 12 02:10:15 2000
+++ rc13-pre6-s_lock/drivers/md/md.c    Sat Dec 30 09:17:27 2000
@@ -1088,7 +1088,7 @@
        }
        memset(rdev, 0, sizeof(*rdev));
 
-       if (get_super(newdev)) {
+       if (is_mounted(newdev)) {
                printk("md: can not import %s, has active inodes!\n",
                        partition_name(newdev));
                err = -EBUSY;
@@ -1726,7 +1726,7 @@
        }
  
        /* this shouldn't be needed as above would have fired */
-       if (!ro && get_super(dev)) {
+       if (!ro && is_mounted(dev)) {
                printk (STILL_MOUNTED, mdidx(mddev));
                OUT(-EBUSY);
        }
diff -urN rc13-pre6/drivers/mtd/ftl.c rc13-pre6-s_lock/drivers/mtd/ftl.c
--- rc13-pre6/drivers/mtd/ftl.c Tue Dec 12 02:10:19 2000
+++ rc13-pre6-s_lock/drivers/mtd/ftl.c  Sat Dec 30 09:17:27 2000
@@ -915,9 +915,6 @@
 
 static release_t ftl_close(struct inode *inode, struct file *file)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-    struct super_block *sb = get_super(inode->i_rdev);
-#endif
     int minor = MINOR(inode->i_rdev);
     partition_t *part = myparts[minor >> 4];
     int i;
@@ -925,11 +922,7 @@
     DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
 
     /* Flush all writes */
-    fsync_dev(inode->i_rdev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-    if (sb) invalidate_inodes(sb);
-#endif
-    invalidate_buffers(inode->i_rdev);
+    invalidate_dev(inode->i_rdev, 2);
 
     /* Wait for any pending erase operations to complete */
     if (part->mtd->sync)
diff -urN rc13-pre6/drivers/mtd/mtdblock.c rc13-pre6-s_lock/drivers/mtd/mtdblock.c
--- rc13-pre6/drivers/mtd/mtdblock.c    Sat Dec 30 07:37:35 2000
+++ rc13-pre6-s_lock/drivers/mtd/mtdblock.c     Sat Dec 30 09:17:27 2000
@@ -355,19 +355,12 @@
 {
        int dev;
        struct mtdblk_dev *mtdblk;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-       struct super_block * sb = get_super(inode->i_rdev);
-#endif
        DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
        if (inode == NULL)
                release_return(-ENODEV);
    
-       fsync_dev(inode->i_rdev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-       if (sb) invalidate_inodes(sb);
-#endif
-       invalidate_buffers(inode->i_rdev);
+       invalidate_dev(inode->i_rdev, 2);
 
        dev = MINOR(inode->i_rdev);
        mtdblk = mtdblks[dev];
diff -urN rc13-pre6/drivers/mtd/nftl.c rc13-pre6-s_lock/drivers/mtd/nftl.c
--- rc13-pre6/drivers/mtd/nftl.c        Tue Dec 12 02:10:19 2000
+++ rc13-pre6-s_lock/drivers/mtd/nftl.c Sat Dec 30 09:17:28 2000
@@ -997,17 +997,13 @@
 
 static int nftl_release(struct inode *inode, struct file *fp)
 {
-       struct super_block *sb = get_super(inode->i_rdev);
        struct NFTLrecord *thisNFTL;
 
        thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
 
        DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
 
-       fsync_dev(inode->i_rdev);
-       if (sb)
-               invalidate_inodes(sb);
-       invalidate_buffers(inode->i_rdev);
+       invalidate_dev(inode->i_rdev, 2);
 
        if (thisNFTL->mtd->sync)
                thisNFTL->mtd->sync(thisNFTL->mtd);
diff -urN rc13-pre6/drivers/scsi/sd.c rc13-pre6-s_lock/drivers/scsi/sd.c
--- rc13-pre6/drivers/scsi/sd.c Wed Nov 29 19:29:16 2000
+++ rc13-pre6-s_lock/drivers/scsi/sd.c  Sat Dec 30 09:17:28 2000
@@ -1262,11 +1262,7 @@
        for (i = max_p - 1; i >= 0; i--) {
                int index = start + i;
                kdev_t devi = MKDEV_SD_PARTITION(index);
-               struct super_block *sb = get_super(devi);
-               sync_dev(devi);
-               if (sb)
-                       invalidate_inodes(sb);
-               invalidate_buffers(devi);
+               invalidate_dev(devi, 1);
                sd_gendisks->part[index].start_sect = 0;
                sd_gendisks->part[index].nr_sects = 0;
                /*
@@ -1315,11 +1311,7 @@
                        for (j = max_p - 1; j >= 0; j--) {
                                int index = start + j;
                                kdev_t devi = MKDEV_SD_PARTITION(index);
-                               struct super_block *sb = get_super(devi);
-                               sync_dev(devi);
-                               if (sb)
-                                       invalidate_inodes(sb);
-                               invalidate_buffers(devi);
+                               invalidate_dev(devi, 1);
                                sd_gendisks->part[index].start_sect = 0;
                                sd_gendisks->part[index].nr_sects = 0;
                                sd_sizes[index] = 0;
diff -urN rc13-pre6/drivers/scsi/sr.c rc13-pre6-s_lock/drivers/scsi/sr.c
--- rc13-pre6/drivers/scsi/sr.c Sat Dec 30 07:37:41 2000
+++ rc13-pre6-s_lock/drivers/scsi/sr.c  Sat Dec 30 09:17:28 2000
@@ -874,15 +874,11 @@
        for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++)
                if (cpnt->device == SDp) {
                        kdev_t devi = MKDEV(MAJOR_NR, i);
-                       struct super_block *sb = get_super(devi);
-
                        /*
                         * Since the cdrom is read-only, no need to sync the device.
                         * We should be kind to our buffer cache, however.
                         */
-                       if (sb)
-                               invalidate_inodes(sb);
-                       invalidate_buffers(devi);
+                       invalidate_dev(devi, 0);
 
                        /*
                         * Reset things back to a sane state so that one can re-load a 
new
diff -urN rc13-pre6/drivers/sound/via82cxxx_audio.c 
rc13-pre6-s_lock/drivers/sound/via82cxxx_audio.c
--- rc13-pre6/drivers/sound/via82cxxx_audio.c   Wed Nov 29 21:37:13 2000
+++ rc13-pre6-s_lock/drivers/sound/via82cxxx_audio.c    Sat Dec 30 09:17:28 2000
@@ -1727,20 +1727,8 @@
 }
 
 
-#ifndef VM_RESERVE
-static int via_mm_swapout (struct page *page, struct file *filp)
-{
-       return 0;
-}
-#endif /* VM_RESERVE */
-
-
 struct vm_operations_struct via_mm_ops = {
        nopage:         via_mm_nopage,
-
-#ifndef VM_RESERVE
-       swapout:        via_mm_swapout,
-#endif
 };
 
 
@@ -1789,9 +1777,7 @@
        vma->vm_ops = &via_mm_ops;
        vma->vm_private_data = card;
 
-#ifdef VM_RESERVE
-       vma->vm_flags |= VM_RESERVE;
-#endif
+       vma->vm_flags |= VM_RESERVED;
 
        if (rd)
                card->ch_in.is_mapped = 1;
diff -urN rc13-pre6/fs/block_dev.c rc13-pre6-s_lock/fs/block_dev.c
--- rc13-pre6/fs/block_dev.c    Wed Nov 29 19:29:31 2000
+++ rc13-pre6-s_lock/fs/block_dev.c     Sat Dec 30 09:17:28 2000
@@ -576,8 +576,11 @@
                bdevname(dev));
 
        sb = get_super(dev);
-       if (sb && invalidate_inodes(sb))
-               printk("VFS: busy inodes on changed media.\n");
+       if (sb) {
+               if (invalidate_inodes(sb))
+                       printk("VFS: busy inodes on changed media.\n");
+               put_super(sb);
+       }
 
        destroy_buffers(dev);
 
diff -urN rc13-pre6/fs/buffer.c rc13-pre6-s_lock/fs/buffer.c
--- rc13-pre6/fs/buffer.c       Sat Dec 30 07:37:45 2000
+++ rc13-pre6-s_lock/fs/buffer.c        Sat Dec 30 09:17:28 2000
@@ -337,9 +337,10 @@
 
        /* sync the superblock to buffers */
        sb = inode->i_sb;
-       wait_on_super(sb);
+       lock_super(sb);
        if (sb->s_op && sb->s_op->write_super)
                sb->s_op->write_super(sb);
+       unlock_super(sb);
 
        /* .. finally sync the buffers to disk */
        dev = inode->i_dev;
@@ -677,6 +678,19 @@
        spin_unlock(&lru_list_lock);
        if (slept)
                goto retry;
+}
+
+void invalidate_dev(kdev_t dev, int sync_flag)
+{
+       struct super_block *sb = get_super(dev);
+       if (sync_flag == 1)
+               sync_dev(dev);
+       else if (sync_flag == 2)
+               fsync_dev(dev);
+       if (sb)
+               invalidate_inodes(sb);
+       put_super(sb);
+       invalidate_buffers(dev);
 }
 
 void set_blocksize(kdev_t dev, int size)
diff -urN rc13-pre6/fs/coda/dir.c rc13-pre6-s_lock/fs/coda/dir.c
--- rc13-pre6/fs/coda/dir.c     Sat Dec 30 07:37:45 2000
+++ rc13-pre6-s_lock/fs/coda/dir.c      Sat Dec 30 09:17:28 2000
@@ -557,8 +557,8 @@
                 return -ENXIO;
         }
                 
-        *ind = NULL;
         *ind = iget(sbptr, ino);
+       put_super(sbptr);
 
         if ( *ind == NULL ) {
                printk("coda_inode_grab: iget(dev: %d, ino: %ld) "
diff -urN rc13-pre6/fs/coda/inode.c rc13-pre6-s_lock/fs/coda/inode.c
--- rc13-pre6/fs/coda/inode.c   Sat Dec 30 07:37:45 2000
+++ rc13-pre6-s_lock/fs/coda/inode.c    Sat Dec 30 09:17:28 2000
@@ -97,7 +97,6 @@
        struct coda_sb_info *sbi = NULL;
        struct venus_comm *vc = NULL;
         ViceFid fid;
-       kdev_t dev = sb->s_dev;
         int error;
        int idx;
        ENTRY;
@@ -139,7 +138,6 @@
         sb->s_blocksize = 1024;        /* XXXXX  what do we put here?? */
         sb->s_blocksize_bits = 10;
         sb->s_magic = CODA_SUPER_MAGIC;
-        sb->s_dev = dev;
         sb->s_op = &coda_super_operations;
 
        /* get root fid from Venus: this needs the root inode */
diff -urN rc13-pre6/fs/devfs/base.c rc13-pre6-s_lock/fs/devfs/base.c
--- rc13-pre6/fs/devfs/base.c   Wed Nov 29 21:44:16 2000
+++ rc13-pre6-s_lock/fs/devfs/base.c    Sat Dec 30 09:17:28 2000
@@ -2166,8 +2166,11 @@
     printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n",
             kdevname (dev) );
     sb = get_super (dev);
-    if ( sb && invalidate_inodes (sb) )
-       printk("VFS: busy inodes on changed media..\n");
+    if (sb) {
+       if (invalidate_inodes (sb))
+               printk("VFS: busy inodes on changed media..\n");
+       put_super(sb);
+    }
     invalidate_buffers (dev);
     /*  Ugly hack to disable messages about unable to read partition table  */
     tmp = warn_no_part;
diff -urN rc13-pre6/fs/dquot.c rc13-pre6-s_lock/fs/dquot.c
--- rc13-pre6/fs/dquot.c        Tue Dec 12 02:10:42 2000
+++ rc13-pre6-s_lock/fs/dquot.c Sat Dec 30 09:17:29 2000
@@ -326,7 +326,7 @@
         memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
 }
 
-void invalidate_dquots(kdev_t dev, short type)
+static void invalidate_dquots(struct super_block *sb, short type)
 {
        struct dquot *dquot, *next;
        int need_restart;
@@ -336,12 +336,10 @@
        need_restart = 0;
        while ((dquot = next) != NULL) {
                next = dquot->dq_next;
-               if (dquot->dq_dev != dev)
+               if (dquot->dq_sb != sb)
                        continue;
                if (dquot->dq_type != type)
                        continue;
-               if (!dquot->dq_sb)      /* Already invalidated entry? */
-                       continue;
                if (dquot->dq_flags & DQ_LOCKED) {
                        __wait_on_dquot(dquot);
 
@@ -350,12 +348,10 @@
                        /*
                         * Make sure it's still the same dquot.
                         */
-                       if (dquot->dq_dev != dev)
+                       if (dquot->dq_sb != sb)
                                continue;
                        if (dquot->dq_type != type)
                                continue;
-                       if (!dquot->dq_sb)
-                               continue;
                }
                /*
                 *  Because inodes needn't to be the only holders of dquot
@@ -1390,7 +1386,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)
@@ -1415,8 +1411,8 @@
                reset_enable_flags(dqopt, cnt);
 
                /* Note: these are blocking operations */
-               remove_dquot_ref(sb->s_dev, cnt);
-               invalidate_dquots(sb->s_dev, cnt);
+               remove_dquot_ref(sb, cnt);
+               invalidate_dquots(sb, cnt);
 
                /* Wait for any pending IO - remove me as soon as invalidate is more 
polite */
                down(&dqopt->dqio_sem);
@@ -1604,6 +1600,8 @@
        if (sb && sb_has_quota_enabled(sb, type))
                ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
 out:
+       if (sb)
+               put_super(sb);
        unlock_kernel();
        return ret;
 }
diff -urN rc13-pre6/fs/ext2/super.c rc13-pre6-s_lock/fs/ext2/super.c
--- rc13-pre6/fs/ext2/super.c   Sat Dec 30 07:37:46 2000
+++ rc13-pre6-s_lock/fs/ext2/super.c    Sat Dec 30 09:17:29 2000
@@ -75,9 +75,6 @@
        va_start (args, fmt);
        vsprintf (error_buf, fmt, args);
        va_end (args);
-       /* this is to prevent panic from syncing this filesystem */
-       if (sb->s_lock)
-               sb->s_lock=0;
        sb->s_flags |= MS_RDONLY;
        panic ("EXT2-fs panic (device %s): %s: %s\n",
               bdevname(sb->s_dev), function, error_buf);
diff -urN rc13-pre6/fs/inode.c rc13-pre6-s_lock/fs/inode.c
--- rc13-pre6/fs/inode.c        Sat Dec 30 07:37:47 2000
+++ rc13-pre6-s_lock/fs/inode.c Sat Dec 30 09:17:29 2000
@@ -1002,14 +1002,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 rc13-pre6/fs/jffs/inode-v23.c rc13-pre6-s_lock/fs/jffs/inode-v23.c
--- rc13-pre6/fs/jffs/inode-v23.c       Sat Dec 30 07:37:48 2000
+++ rc13-pre6-s_lock/fs/jffs/inode-v23.c        Sat Dec 30 09:17:29 2000
@@ -159,7 +159,6 @@
 
        D1(printk (KERN_NOTICE "jffs_put_super(): Successfully waited on thread.\n"));
 
-       sb->s_dev = 0;
        jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
        D1(printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n",
               kdevname(dev)));
diff -urN rc13-pre6/fs/super.c rc13-pre6-s_lock/fs/super.c
--- rc13-pre6/fs/super.c        Tue Dec 12 02:10:46 2000
+++ rc13-pre6-s_lock/fs/super.c Sat Dec 30 12:03:30 2000
@@ -41,14 +41,6 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
-/*
- * We use a semaphore to synchronize all mount/umount
- * activity - imagine the mess if we have a race between
- * unmounting a filesystem and re-mounting it (or something
- * else).
- */
-static DECLARE_MUTEX(mount_sem);
-
 extern void wait_for_keypress(void);
 
 extern int root_mountflags;
@@ -346,6 +338,8 @@
                INIT_LIST_HEAD(&mnt->mnt_clash);
        }
        INIT_LIST_HEAD(&mnt->mnt_mounts);
+       if (list_empty(&sb->s_mounts))
+               atomic_inc(&sb->s_count);
        list_add(&mnt->mnt_instances, &sb->s_mounts);
        list_add(&mnt->mnt_list, vfsmntlist.prev);
        spin_unlock(&dcache_lock);
@@ -411,6 +405,8 @@
 static void remove_vfsmnt(struct vfsmount *mnt)
 {
        /* First of all, remove it from all lists */
+       if (mnt->mnt_instances.next != mnt->mnt_instances.prev)
+               atomic_inc(&mnt->mnt_sb->s_count);
        list_del(&mnt->mnt_instances);
        list_del(&mnt->mnt_clash);
        list_del(&mnt->mnt_list);
@@ -579,27 +575,11 @@
 #undef FREEROOM
 }
 
-/**
- *     __wait_on_super - wait on a superblock
- *     @sb: superblock to wait on
- *
- *     Waits for a superblock to become unlocked and then returns. It does
- *     not take the lock. This is an internal function. See wait_on_super().
- */
- 
-void __wait_on_super(struct super_block * sb)
+void put_super(struct super_block *sb)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&sb->s_wait, &wait);
-repeat:
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       if (sb->s_lock) {
-               schedule();
-               goto repeat;
-       }
-       remove_wait_queue(&sb->s_wait, &wait);
-       current->state = TASK_RUNNING;
+       up(&sb->s_umount);
+       if (atomic_dec_and_test(&sb->s_count))
+               kfree(sb);
 }
 
 /*
@@ -611,20 +591,23 @@
 {
        struct super_block * sb;
 
+restart:
        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;
+               atomic_inc(&sb->s_count);
+               down(&sb->s_umount);
                lock_super(sb);
-               if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev))
+               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);
+               put_super(sb);
+               goto restart;
        }
 }
 
@@ -646,9 +629,11 @@
        s = sb_entry(super_blocks.next);
        while (s != sb_entry(&super_blocks))
                if (s->s_dev == dev) {
-                       wait_on_super(s);
-                       if (s->s_dev == dev)
+                       atomic_inc(&s->s_count);
+                       down(&s->s_umount);
+                       if (s->s_root)
                                return s;
+                       put_super(s);
                        goto restart;
                } else
                        s = sb_entry(s->s_list.next);
@@ -668,6 +653,7 @@
         if (s == NULL)
                 goto out;
        err = vfs_statfs(s, &sbuf);
+       put_super(s);
        if (err)
                goto out;
 
@@ -691,42 +677,61 @@
  
 struct super_block *get_empty_super(void)
 {
-       struct super_block *s;
-
-       for (s  = sb_entry(super_blocks.next);
-            s != sb_entry(&super_blocks); 
-            s  = sb_entry(s->s_list.next)) {
-               if (s->s_dev)
-                       continue;
-               if (!s->s_lock)
-                       return s;
-               printk("VFS: empty superblock %p locked!\n", s);
-       }
-       /* 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));
                INIT_LIST_HEAD(&s->s_dirty);
-               list_add (&s->s_list, super_blocks.prev);
-               init_waitqueue_head(&s->s_wait);
                INIT_LIST_HEAD(&s->s_files);
                INIT_LIST_HEAD(&s->s_mounts);
+               sema_init(&s->s_umount, 0);
+               sema_init(&s->s_lock, 1);
+               atomic_set(&s->s_count, 1);
+               list_add (&s->s_list, super_blocks.prev);
        }
        return s;
 }
 
+/*
+ * Unnamed block devices are dummy devices used by virtual
+ * filesystems which don't use real block-devices.  -- jrs
+ */
+
+static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))];
+
+static kdev_t get_unnamed_dev(void)
+{
+       int i;
+
+       for (i = 1; i < 256; i++) {
+               if (!test_and_set_bit(i,unnamed_dev_in_use))
+                       return MKDEV(UNNAMED_MAJOR, i);
+       }
+       return 0;
+}
+
+static void put_unnamed_dev(kdev_t dev)
+{
+       if (!dev || MAJOR(dev) != UNNAMED_MAJOR)
+               return;
+       if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))
+               return;
+       printk("VFS: put_unnamed_dev: freeing unused device %s\n",
+                       kdevname(dev));
+}
+
 static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
                                       struct file_system_type *type, int flags,
                                       void *data, int silent)
 {
        struct super_block * s;
+       kdev_t rdev = dev ? dev : get_unnamed_dev();
+       if (!rdev)
+               goto fail;
        s = get_empty_super();
        if (!s)
-               goto out;
-       s->s_dev = dev;
+               goto fail;
+       s->s_dev = rdev;
        s->s_bdev = bdev;
        s->s_flags = flags;
        s->s_dirt = 0;
@@ -743,48 +748,24 @@
        /* tell bdcache that we are going to keep this one */
        if (bdev)
                atomic_inc(&bdev->bd_count);
-out:
        return s;
 
 out_fail:
        s->s_dev = 0;
-       s->s_bdev = 0;
+       if (!dev)
+               put_unnamed_dev(rdev);
+       s->s_bdev = NULL;
        s->s_type = NULL;
        unlock_super(s);
+       put_super(s);
+fail:
        return NULL;
 }
 
-/*
- * Unnamed block devices are dummy devices used by virtual
- * filesystems which don't use real block-devices.  -- jrs
- */
-
-static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))];
-
-kdev_t get_unnamed_dev(void)
-{
-       int i;
-
-       for (i = 1; i < 256; i++) {
-               if (!test_and_set_bit(i,unnamed_dev_in_use))
-                       return MKDEV(UNNAMED_MAJOR, i);
-       }
-       return 0;
-}
-
-void put_unnamed_dev(kdev_t dev)
-{
-       if (!dev || MAJOR(dev) != UNNAMED_MAJOR)
-               return;
-       if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))
-               return;
-       printk("VFS: put_unnamed_dev: freeing unused device %s\n",
-                       kdevname(dev));
-}
-
 static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
        char *dev_name, int flags, void * data)
 {
+       DECLARE_MUTEX(mount_sem);
        struct inode *inode;
        struct block_device *bdev;
        struct block_device_operations *bdops;
@@ -809,16 +790,18 @@
        bdev = inode->i_bdev;
        bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) );
        if (bdops) bdev->bd_op = bdops;
+       dev = to_kdev_t(bdev->bd_dev);
        /* Done with lookups, semaphore down */
        down(&mount_sem);
-       dev = to_kdev_t(bdev->bd_dev);
        sb = get_super(dev);
        if (sb) {
                if (fs_type == sb->s_type &&
                    ((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
+                       up(&mount_sem);
                        path_release(&nd);
                        return sb;
                }
+               put_super(sb);
        } else {
                mode_t mode = FMODE_READ; /* we always need it ;-) */
                if (!(flags & MS_RDONLY))
@@ -833,6 +816,7 @@
                error = -EINVAL;
                sb = read_super(dev, bdev, fs_type, flags, data, 0);
                if (sb) {
+                       up(&mount_sem);
                        get_filesystem(fs_type);
                        path_release(&nd);
                        return sb;
@@ -841,29 +825,21 @@
                blkdev_put(bdev, BDEV_FS);
        }
 out:
-       path_release(&nd);
        up(&mount_sem);
+       path_release(&nd);
        return ERR_PTR(error);
 }
 
 static struct super_block *get_sb_nodev(struct file_system_type *fs_type,
        int flags, void * data)
 {
-       kdev_t dev;
-       int error = -EMFILE;
-       down(&mount_sem);
-       dev = get_unnamed_dev();
-       if (dev) {
-               struct super_block * sb;
-               error = -EINVAL;
-               sb = read_super(dev, NULL, fs_type, flags, data, 0);
-               if (sb) {
-                       get_filesystem(fs_type);
-                       return sb;
-               }
-               put_unnamed_dev(dev);
+       struct super_block * sb;
+       int error = -EINVAL;
+       sb = read_super(0, NULL, fs_type, flags, data, 0);
+       if (sb) {
+               get_filesystem(fs_type);
+               return sb;
        }
-       up(&mount_sem);
        return ERR_PTR(error);
 }
 
@@ -875,10 +851,11 @@
         * Get the superblock of kernel-wide instance, but
         * keep the reference to fs_type.
         */
-       down(&mount_sem);
        sb = fs_type->kern_mnt->mnt_sb;
        if (!sb)
                BUG();
+       atomic_inc(&sb->s_count);
+       down(&sb->s_umount);
        get_filesystem(fs_type);
        do_remount_sb(sb, flags, data);
        return sb;
@@ -913,6 +890,7 @@
                        "Self-destruct in 5 seconds.  Have a nice day...\n");
        }
 
+       list_del(&sb->s_list);
        dev = sb->s_dev;
        sb->s_dev = 0;          /* Free the superblock */
        bdev = sb->s_bdev;
@@ -969,21 +947,18 @@
 
 struct vfsmount *kern_mount(struct file_system_type *type)
 {
-       kdev_t dev = get_unnamed_dev();
        struct super_block *sb;
        struct vfsmount *mnt;
-       if (!dev)
-               return ERR_PTR(-EMFILE);
-       sb = read_super(dev, NULL, type, 0, NULL, 0);
-       if (!sb) {
-               put_unnamed_dev(dev);
+       sb = read_super(0, NULL, type, 0, NULL, 0);
+       if (!sb)
                return ERR_PTR(-EINVAL);
-       }
        mnt = add_vfsmnt(NULL, sb->s_root, NULL);
        if (!mnt) {
                kill_super(sb, 0);
+               put_super(sb);
                return ERR_PTR(-ENOMEM);
        }
+       put_super(sb);
        type->kern_mnt = mnt;
        return mnt;
 }
@@ -993,9 +968,11 @@
 void kern_umount(struct vfsmount *mnt)
 {
        struct super_block *sb = mnt->mnt_sb;
+       down(&sb->s_umount);
        spin_lock(&dcache_lock);
        remove_vfsmnt(mnt);
        kill_super(sb, 0);
+       put_super(sb);
 }
 
 /*
@@ -1014,6 +991,8 @@
 {
        struct super_block * sb = mnt->mnt_sb;
 
+       down(&sb->s_umount);
+
        /*
         * No sense to grab the lock for this test, but test itself looks
         * somewhat bogus. Suggestions for better replacement?
@@ -1033,6 +1012,7 @@
                mntput(mnt);
                if (!(sb->s_flags & MS_RDONLY))
                        retval = do_remount_sb(sb, MS_RDONLY, 0);
+               up(&sb->s_umount);
                return retval;
        }
 
@@ -1041,14 +1021,14 @@
        if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
                if (atomic_read(&mnt->mnt_count) > 2) {
                        spin_unlock(&dcache_lock);
-                       mntput(mnt);
-                       return -EBUSY;
+                       goto busy;
                }
                if (sb->s_type->fs_flags & FS_SINGLE)
                        put_filesystem(sb->s_type);
                /* We hold two references, so mntput() is safe */
                mntput(mnt);
                remove_vfsmnt(mnt);
+               put_super(sb);
                return 0;
        }
        spin_unlock(&dcache_lock);
@@ -1084,18 +1064,15 @@
        shrink_dcache_sb(sb);
        fsync_dev(sb->s_dev);
 
-       if (sb->s_root->d_inode->i_state) {
-               mntput(mnt);
-               return -EBUSY;
-       }
+       if (sb->s_root->d_inode->i_state)
+               goto busy;
 
        /* Something might grab it again - redo checks */
 
        spin_lock(&dcache_lock);
        if (atomic_read(&mnt->mnt_count) > 2) {
                spin_unlock(&dcache_lock);
-               mntput(mnt);
-               return -EBUSY;
+               goto busy;
        }
 
        /* OK, that's the point of no return */
@@ -1103,7 +1080,12 @@
        remove_vfsmnt(mnt);
 
        kill_super(sb, umount_root);
+       put_super(sb);
        return 0;
+busy:
+       mntput(mnt);
+       up(&sb->s_umount);
+       return -EBUSY;
 }
 
 /*
@@ -1141,9 +1123,7 @@
 
        dput(nd.dentry);
        /* puts nd.mnt */
-       down(&mount_sem);
        retval = do_umount(nd.mnt, 0, flags);
-       up(&mount_sem);
        goto out;
 dput_and_out:
        path_release(&nd);
@@ -1208,7 +1188,6 @@
        if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
                get_filesystem(old_nd.mnt->mnt_sb->s_type);
                
-       down(&mount_sem);
        /* there we go */
        down(&new_nd.dentry->d_inode->i_zombie);
        if (IS_DEADDIR(new_nd.dentry->d_inode))
@@ -1216,7 +1195,6 @@
        else if (add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname))
                err = 0;
        up(&new_nd.dentry->d_inode->i_zombie);
-       up(&mount_sem);
        if (err && old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
                put_filesystem(old_nd.mnt->mnt_sb->s_type);
 out2:
@@ -1346,12 +1324,6 @@
        if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
                return -EINVAL;
 
-#if 0  /* Can be deleted again. Introduced in patch-2.3.99-pre6 */
-       /* loopback mount? This is special - requires fewer capabilities */
-       if (strcmp(type_page, "bind")==0)
-               return do_loopback(dev_name, dir_name);
-#endif
-
        /* for the rest we _really_ need capabilities... */
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1368,7 +1340,7 @@
        if (retval)
                goto fs_out;
 
-       /* get superblock, locks mount_sem on success */
+       /* get superblock, locks ->s_umount on success */
        if (fstype->fs_flags & FS_NOMOUNT)
                sb = ERR_PTR(-EINVAL);
        else if (fstype->fs_flags & FS_REQUIRES_DEV)
@@ -1405,7 +1377,7 @@
                goto fail;
        retval = 0;
 unlock_out:
-       up(&mount_sem);
+       put_super(sb);
 dput_out:
        path_release(&nd);
 fs_out:
@@ -1478,26 +1450,19 @@
        fs_type = get_fs_type("nfs");
        if (!fs_type)
                goto no_nfs;
-       ROOT_DEV = get_unnamed_dev();
-       if (!ROOT_DEV)
-               /*
-                * Your /linuxrc sucks worse than MSExchange - that's the
-                * only way you could run out of anon devices at that point.
-                */
-               goto no_anon;
        data = nfs_root_data();
        if (!data)
-               goto no_server;
-       sb = read_super(ROOT_DEV, NULL, fs_type, root_mountflags, data, 1);
-       if (sb)
+               goto no_anon;
+       sb = read_super(0, NULL, fs_type, root_mountflags, data, 1);
+       if (sb) {
                /*
                 * We _can_ fail there, but if that will happen we have no
                 * chance anyway (no memory for vfsmnt and we _will_ need it,
                 * no matter which fs we try to mount).
                 */
+               ROOT_DEV = sb->s_dev;
                goto mount_it;
-no_server:
-       put_unnamed_dev(ROOT_DEV);
+       }
 no_anon:
        put_filesystem(fs_type);
 no_nfs:
@@ -1607,12 +1572,12 @@
        }
        else
                vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root");
-       /* FIXME: if something will try to umount us right now... */
        if (vfsmnt) {
                set_fs_root(current->fs, vfsmnt, sb->s_root);
                set_fs_pwd(current->fs, vfsmnt, sb->s_root);
                if (bdev)
                        bdput(bdev); /* sb holds a reference */
+               put_super(sb);
                return;
        }
        panic("VFS: add_vfsmnt failed for root fs");
@@ -1697,7 +1662,6 @@
        root_mnt = mntget(current->fs->rootmnt);
        root = dget(current->fs->root);
        read_unlock(&current->fs->lock);
-       down(&mount_sem);
        down(&old_nd.dentry->d_inode->i_zombie);
        error = -ENOENT;
        if (IS_DEADDIR(new_nd.dentry->d_inode))
@@ -1732,7 +1696,6 @@
        error = 0;
 out2:
        up(&old_nd.dentry->d_inode->i_zombie);
-       up(&mount_sem);
        dput(root);
        mntput(root_mnt);
        path_release(&old_nd);
@@ -1765,10 +1728,8 @@
                if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC &&
                    devfs_nd.dentry == devfs_nd.mnt->mnt_root) {
                        dput(devfs_nd.dentry);
-                       down(&mount_sem);
                        /* puts devfs_nd.mnt */
                        do_umount(devfs_nd.mnt, 0, 0);
-                       up(&mount_sem);
                } else 
                        path_release(&devfs_nd);
        }
diff -urN rc13-pre6/fs/udf/inode.c rc13-pre6-s_lock/fs/udf/inode.c
--- rc13-pre6/fs/udf/inode.c    Tue Dec 12 02:10:46 2000
+++ rc13-pre6-s_lock/fs/udf/inode.c     Sat Dec 30 09:17:29 2000
@@ -203,7 +203,6 @@
        udf_release_data(bh);
 
        inode->i_data.a_ops->writepage(page);
-       UnlockPage(page);
        page_cache_release(page);
 
        mark_inode_dirty(inode);
diff -urN rc13-pre6/fs/ufs/super.c rc13-pre6-s_lock/fs/ufs/super.c
--- rc13-pre6/fs/ufs/super.c    Sun Sep 17 12:15:20 2000
+++ rc13-pre6-s_lock/fs/ufs/super.c     Sat Dec 30 09:17:29 2000
@@ -230,9 +230,6 @@
        va_start (args, fmt);
        vsprintf (error_buf, fmt, args);
        va_end (args);
-       /* this is to prevent panic from syncing this filesystem */
-       if (sb->s_lock)
-               sb->s_lock = 0;
        sb->s_flags |= MS_RDONLY;
        printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
                kdevname(sb->s_dev), function, error_buf);
diff -urN rc13-pre6/include/linux/fs.h rc13-pre6-s_lock/include/linux/fs.h
--- rc13-pre6/include/linux/fs.h        Sat Dec 30 07:37:54 2000
+++ rc13-pre6-s_lock/include/linux/fs.h Sat Dec 30 09:44:34 2000
@@ -667,7 +667,6 @@
        kdev_t                  s_dev;
        unsigned long           s_blocksize;
        unsigned char           s_blocksize_bits;
-       unsigned char           s_lock;
        unsigned char           s_dirt;
        struct file_system_type *s_type;
        struct super_operations *s_op;
@@ -675,7 +674,9 @@
        unsigned long           s_flags;
        unsigned long           s_magic;
        struct dentry           *s_root;
-       wait_queue_head_t       s_wait;
+       struct semaphore        s_umount;
+       struct semaphore        s_lock;         /* probably goner */
+       atomic_t                s_count;
 
        struct list_head        s_dirty;        /* dirty inodes */
        struct list_head        s_files;
@@ -1070,6 +1071,7 @@
 extern void write_inode_now(struct inode *, int);
 extern void sync_dev(kdev_t);
 extern int fsync_dev(kdev_t);
+extern void invalidate_dev(kdev_t, int);
 extern int fsync_inode_buffers(struct inode *);
 extern int osync_inode_buffers(struct inode *);
 extern int inode_has_buffers(struct inode *);
@@ -1265,7 +1267,16 @@
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
 struct super_block *get_empty_super(void);
-extern void put_super(kdev_t);
+extern void put_super(struct super_block *sb);
+static inline int is_mounted(kdev_t dev)
+{
+       struct super_block *sb = get_super(dev);
+       if (sb) {
+               put_super(sb);
+               return 1;
+       }
+       return 0;
+}
 unsigned long generate_cluster(kdev_t, int b[], int);
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
 extern kdev_t ROOT_DEV;
diff -urN rc13-pre6/include/linux/locks.h rc13-pre6-s_lock/include/linux/locks.h
--- rc13-pre6/include/linux/locks.h     Sat Dec 16 12:30:30 2000
+++ rc13-pre6-s_lock/include/linux/locks.h      Sat Dec 30 09:44:35 2000
@@ -39,30 +39,15 @@
  * a super-block (although even this isn't done right now.
  * nfs may need it).
  */
-extern void __wait_on_super(struct super_block *);
-
-extern inline void wait_on_super(struct super_block * sb)
-{
-       if (sb->s_lock)
-               __wait_on_super(sb);
-}
 
 extern inline void lock_super(struct super_block * sb)
 {
-       if (sb->s_lock)
-               __wait_on_super(sb);
-       sb->s_lock = 1;
+       down(&sb->s_lock);
 }
 
 extern inline void unlock_super(struct super_block * sb)
 {
-       sb->s_lock = 0;
-       /*
-        * No need of any barrier, we're protected by
-        * the big kernel lock here... unfortunately :)
-        */
-       if (waitqueue_active(&sb->s_wait))
-               wake_up(&sb->s_wait);
+       up(&sb->s_lock);
 }
 
 #endif /* _LINUX_LOCKS_H */
diff -urN rc13-pre6/include/linux/quotaops.h rc13-pre6-s_lock/include/linux/quotaops.h
--- rc13-pre6/include/linux/quotaops.h  Sat Dec 16 12:52:02 2000
+++ rc13-pre6-s_lock/include/linux/quotaops.h   Sat Dec 30 09:58:07 2000
@@ -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);
 
diff -urN rc13-pre6/kernel/ksyms.c rc13-pre6-s_lock/kernel/ksyms.c
--- rc13-pre6/kernel/ksyms.c    Sat Dec 30 07:37:55 2000
+++ rc13-pre6-s_lock/kernel/ksyms.c     Sat Dec 30 09:17:30 2000
@@ -127,6 +127,8 @@
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_fs_type);
 EXPORT_SYMBOL(get_super);
+EXPORT_SYMBOL(put_super);
+EXPORT_SYMBOL(invalidate_dev);
 EXPORT_SYMBOL(get_empty_super);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(names_cachep);
@@ -472,7 +474,6 @@
 
 /* Added to make file system as module */
 EXPORT_SYMBOL(sys_tz);
-EXPORT_SYMBOL(__wait_on_super);
 EXPORT_SYMBOL(file_fsync);
 EXPORT_SYMBOL(fsync_inode_buffers);
 EXPORT_SYMBOL(clear_inode);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to