This patch is a preparation necessary to remove the BKL from do_new_mount().
It explicitly adds calls to lock_kernel()/unlock_kernel() around
get_sb/fill_super operations for filesystems that still uses the BKL.
I've read through all the code formerly covered by the BKL inside
do_kern_mount() and have satisfied myself that it doesn't need the BKL
any more.
do_kern_mount() is already called without the BKL when mounting the rootfs
and in nfsctl. do_kern_mount() calls vfs_kern_mount(), which is called
from various places without BKL: simple_pin_fs(), nfs_do_clone_mount()
through nfs_follow_mountpoint(), afs_mntpt_do_automount() through
afs_mntpt_follow_link(). Both later functions are actually the filesystems
follow_link inode operation. vfs_kern_mount() is calling the specified
get_sb function and lets the filesystem do its job by calling the given
fill_super function.
Therefore I think it is safe to push down the BKL from the VFS to the
low-level filesystems get_sb/fill_super operation.
[arnd: do not add the BKL to those file systems that already
       don't use it elsewhere]
Signed-off-by: Jan Blunck <jblunck@infradead.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: Christoph Hellwig <hch@infradead.org>
        struct adfs_sb_info *asb;
        struct inode *root;
 
+       lock_kernel();
+
        sb->s_flags |= MS_NODIRATIME;
 
        asb = kzalloc(sizeof(*asb), GFP_KERNEL);
-       if (!asb)
+       if (!asb) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        sb->s_fs_info = asb;
 
        /* set default options */
                goto error;
        } else
                sb->s_root->d_op = &adfs_dentry_operations;
+       unlock_kernel();
        return 0;
 
 error_free_bh:
 error:
        sb->s_fs_info = NULL;
        kfree(asb);
+       unlock_kernel();
        return -EINVAL;
 }
 
 
        u8                       sig[4];
        int                      ret = -EINVAL;
 
+       lock_kernel();
+
        save_mount_options(sb, data);
 
        pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
        sb->s_flags |= MS_NODIRATIME;
 
        sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        sb->s_fs_info = sbi;
        mutex_init(&sbi->s_bmlock);
        spin_lock_init(&sbi->symlink_lock);
                printk(KERN_ERR "AFFS: Error parsing options\n");
                kfree(sbi->s_prefix);
                kfree(sbi);
+               unlock_kernel();
                return -EINVAL;
        }
        /* N.B. after this point s_prefix must be released */
        sb->s_root->d_op = &affs_dentry_operations;
 
        pr_debug("AFFS: s_flags=%lX\n",sb->s_flags);
+       unlock_kernel();
        return 0;
 
        /*
        kfree(sbi->s_prefix);
        kfree(sbi);
        sb->s_fs_info = NULL;
+       unlock_kernel();
        return ret;
 }
 
 
        struct inode *inode = NULL;
        int ret;
 
+       lock_kernel();
+
        _enter("");
 
        /* allocate a superblock info record */
        as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
        if (!as) {
                _leave(" = -ENOMEM");
+               unlock_kernel();
                return -ENOMEM;
        }
 
        sb->s_root = root;
 
        _leave(" = 0");
+       unlock_kernel();
        return 0;
 
 error_inode:
        sb->s_fs_info = NULL;
 
        _leave(" = %d", ret);
+       unlock_kernel();
        return ret;
 }
 
 
        int ret = -EINVAL;
        unsigned long i_sblock, i_eblock, i_eoff, s_size;
 
+       lock_kernel();
+
        info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
+       if (!info) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        mutex_init(&info->bfs_lock);
        s->s_fs_info = info;
 
        brelse(bh);
        brelse(sbh);
        dump_imap("read_super", s);
+       unlock_kernel();
        return 0;
 
 out3:
        mutex_destroy(&info->bfs_lock);
        kfree(info);
        s->s_fs_info = NULL;
+       unlock_kernel();
        return ret;
 }
 
 
            int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
        int rc;
-       struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
+       struct super_block *sb;
+
+       lock_kernel();
+
+       sb = sget(fs_type, NULL, set_anon_super, NULL);
 
        cFYI(1, "Devname: %s flags: %d ", dev_name, flags);
 
-       if (IS_ERR(sb))
+       if (IS_ERR(sb)) {
+               unlock_kernel();
                return PTR_ERR(sb);
+       }
 
        sb->s_flags = flags;
 
        rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0);
        if (rc) {
                deactivate_locked_super(sb);
+               unlock_kernel();
                return rc;
        }
        sb->s_flags |= MS_ACTIVE;
        simple_set_mnt(mnt, sb);
+       unlock_kernel();
        return 0;
 }
 
 
        int error;
        int idx;
 
+       lock_kernel();
+
        idx = get_device_index((struct coda_mount_data *) data);
 
        /* Ignore errors in data, for backward compatibility */
        vc = &coda_comms[idx];
        if (!vc->vc_inuse) {
                printk("coda_read_super: No pseudo device\n");
+               unlock_kernel();
                return -EINVAL;
        }
 
         if ( vc->vc_sb ) {
                printk("coda_read_super: Device already mounted\n");
+               unlock_kernel();
                return -EBUSY;
        }
 
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root)
                goto error;
-        return 0;
+       unlock_kernel();
+       return 0;
 
  error:
        bdi_destroy(&vc->bdi);
        if (vc)
                vc->vc_sb = NULL;
 
+       unlock_kernel();
        return -EINVAL;
 }
 
 
 #include <linux/parser.h>
 #include <linux/fs_stack.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>     /* For lock_kernel() */
 #include "ecryptfs_kernel.h"
 
 /**
        const char *err = "Getting sb failed";
        int rc;
 
+       lock_kernel();
        sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
        if (!sbi) {
                rc = -ENOMEM;
                goto out;
        }
        simple_set_mnt(mnt, s);
+       unlock_kernel();
        return 0;
 
 out:
                kmem_cache_free(ecryptfs_sb_info_cache, sbi);
        }
        printk(KERN_ERR "%s; rc = [%d]\n", err, rc);
+       unlock_kernel();
        return rc;
 }
 
 
        __le32 features;
        int err;
 
+       lock_kernel();
+
+       err = -ENOMEM;
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
-               return -ENOMEM;
+               goto failed_unlock;
 
        sbi->s_blockgroup_lock =
                kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
        if (!sbi->s_blockgroup_lock) {
                kfree(sbi);
-               return -ENOMEM;
+               goto failed_unlock;
        }
        sb->s_fs_info = sbi;
        sbi->s_sb_block = sb_block;
        if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY))
                sb->s_flags |= MS_RDONLY;
        ext2_write_super(sb);
+       unlock_kernel();
        return 0;
 
 cantfind_ext2:
        sb->s_fs_info = NULL;
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
+failed_unlock:
+       unlock_kernel();
        return ret;
 }
 
 
        __le32 features;
        int err;
 
+       lock_kernel();
+
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
 
        sbi->s_blockgroup_lock =
                kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
        if (!sbi->s_blockgroup_lock) {
                kfree(sbi);
+               unlock_kernel();
                return -ENOMEM;
        }
        sb->s_fs_info = sbi;
                "writeback");
 
        lock_kernel();
+       unlock_kernel();
        return 0;
 
 cantfind_ext3:
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        lock_kernel();
+       unlock_kernel();
        return ret;
 }
 
 
        int err;
        unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
 
+       lock_kernel();
+
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                goto out_free_orig;
        if (es->s_error_count)
                mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */
 
-       lock_kernel();
        kfree(orig_data);
        return 0;
 
        sb->s_fs_info = NULL;
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
-       lock_kernel();
+       kfree(orig_data);
+       return ret;
+
 out_free_orig:
+       unlock_kernel();
        kfree(orig_data);
        return ret;
 }
 
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/buffer_head.h>
+#include <linux/smp_lock.h>     /* For lock_kernel() */
 #include "fat.h"
 
 /* Characters that are undesirable in an MS-DOS file name */
 {
        int res;
 
+       lock_kernel();
        res = fat_fill_super(sb, data, silent, &msdos_dir_inode_operations, 0);
-       if (res)
+       if (res) {
+               unlock_kernel();
                return res;
+       }
 
        sb->s_flags |= MS_NOATIME;
        sb->s_root->d_op = &msdos_dentry_operations;
+       unlock_kernel();
        return 0;
 }
 
 
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 #include <linux/namei.h>
+#include <linux/smp_lock.h>     /* For lock_kernel() */
 #include "fat.h"
 
 /*
 {
        int res;
 
+       lock_kernel();
        res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);
-       if (res)
+       if (res) {
+               unlock_kernel();
                return res;
+       }
 
        if (MSDOS_SB(sb)->options.name_check != 's')
                sb->s_root->d_op = &vfat_ci_dentry_ops;
        else
                sb->s_root->d_op = &vfat_dentry_ops;
 
+       unlock_kernel();
        return 0;
 }
 
 
  *   The superblock on success, else %NULL.
  *
  * Locking:
- *   We are under the bkl and @sbp->s_lock.
+ *   We are under @sbp->s_lock.
  */
 static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 {
        struct inode *root;
        int ret = -EINVAL;
 
+       lock_kernel();
+
        sbp->s_flags |= MS_RDONLY;
 
        infp = kzalloc(sizeof(*infp), GFP_KERNEL);
        if (!infp) {
                printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
+               unlock_kernel();
                return -ENOMEM;
        }
 
                goto out_free_ilist;
        }
 
+       unlock_kernel();
        return 0;
        
 out_free_ilist:
 out:
        brelse(bp);
        kfree(infp);
+       unlock_kernel();
        return ret;
 }
 
 
        struct inode *root_inode;
        int res;
 
+       lock_kernel();
+
        sbi = kzalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        sb->s_fs_info = sbi;
        INIT_HLIST_HEAD(&sbi->rsrc_inodes);
 
        sb->s_root->d_op = &hfs_dentry_operations;
 
        /* everything's okay */
+       unlock_kernel();
        return 0;
 
 bail_iput:
        printk(KERN_ERR "hfs: get root inode failed.\n");
 bail:
        hfs_mdb_put(sb);
+       unlock_kernel();
        return res;
 }
 
 
 
        int o;
 
+       lock_kernel();
+
        save_mount_options(s, options);
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        s->s_fs_info = sbi;
 
        sbi->sb_bmp_dir = NULL;
                        root->i_blocks = 5;
                hpfs_brelse4(&qbh);
        }
+       unlock_kernel();
        return 0;
 
 bail4: brelse(bh2);
        kfree(sbi->sb_cp_table);
        s->s_fs_info = NULL;
        kfree(sbi);
+       unlock_kernel();
        return -EINVAL;
 }
 
 
        int table, error = -EINVAL;
        unsigned int vol_desc_start;
 
+       lock_kernel();
+
        save_mount_options(s, data);
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        s->s_fs_info = sbi;
 
        if (!parse_options((char *)data, &opt))
 
        kfree(opt.iocharset);
 
+       unlock_kernel();
        return 0;
 
        /*
        kfree(opt.iocharset);
        kfree(sbi);
        s->s_fs_info = NULL;
+       unlock_kernel();
        return error;
 }
 
 
 static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct jffs2_sb_info *c;
+       int ret;
+
+       lock_kernel();
 
        D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
                  " New superblock for device %d (\"%s\")\n",
                  sb->s_mtd->index, sb->s_mtd->name));
 
        c = kzalloc(sizeof(*c), GFP_KERNEL);
-       if (!c)
+       if (!c) {
+               unlock_kernel();
                return -ENOMEM;
+       }
 
        c->mtd = sb->s_mtd;
        c->os_priv = sb;
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
        sb->s_flags |= MS_POSIXACL;
 #endif
-       return jffs2_do_fill_super(sb, data, silent);
+       ret = jffs2_do_fill_super(sb, data, silent);
+       unlock_kernel();
+       return ret;
 }
 
 static int jffs2_get_sb(struct file_system_type *fs_type,
 
        s64 newLVSize = 0;
        int flag, ret = -EINVAL;
 
+       lock_kernel();
+
        jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);
 
-       if (!new_valid_dev(sb->s_bdev->bd_dev))
+       if (!new_valid_dev(sb->s_bdev->bd_dev)) {
+               unlock_kernel();
                return -EOVERFLOW;
+       }
 
        sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        sb->s_fs_info = sbi;
        sbi->sb = sb;
        sbi->uid = sbi->gid = sbi->umask = -1;
        sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, (u64)sb->s_maxbytes);
 #endif
        sb->s_time_gran = 1;
+       unlock_kernel();
        return 0;
 
 out_no_root:
                unload_nls(sbi->nls_tab);
 out_kfree:
        kfree(sbi);
+       unlock_kernel();
        return ret;
 }
 
 
        if (!(flags & MS_RDONLY))
                mode |= FMODE_WRITE;
 
+       lock_kernel();
        sd.bdev = open_bdev_exclusive(dev_name, mode, fs_type);
-       if (IS_ERR(sd.bdev))
+       if (IS_ERR(sd.bdev)) {
+               unlock_kernel();
                return PTR_ERR(sd.bdev);
+       }
 
        /*
         * To get mount instance using sget() vfs-routine, NILFS needs
        if (need_to_close)
                close_bdev_exclusive(sd.bdev, mode);
        simple_set_mnt(mnt, s);
+       unlock_kernel();
        return 0;
 
  failed_unlock:
  failed:
        close_bdev_exclusive(sd.bdev, mode);
 
+       unlock_kernel();
        return err;
 
  cancel_new:
         * We must finish all post-cleaning before this call;
         * put_nilfs() needs the block device.
         */
+       unlock_kernel();
        return err;
 }
 
 
        struct inode *tmp_ino;
        int blocksize, result;
 
+       lock_kernel();
+
        /*
         * We do a pretty difficult piece of bootstrap by reading the
         * MFT (and other metadata) from disk into memory. We'll only
                        ntfs_error(sb, "Allocation of NTFS volume structure "
                                        "failed. Aborting mount...");
                lockdep_on();
+               unlock_kernel();
                return -ENOMEM;
        }
        /* Initialize ntfs_volume structure. */
                sb->s_export_op = &ntfs_export_ops;
                lock_kernel();
                lockdep_on();
+               unlock_kernel();
                return 0;
        }
        ntfs_error(sb, "Failed to allocate root directory.");
        kfree(vol);
        ntfs_debug("Failed, returning -EINVAL.");
        lockdep_on();
+       unlock_kernel();
        return -EINVAL;
 }
 
 
 #include <linux/string.h>
 #include <linux/backing-dev.h>
 #include <linux/poll.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
        struct inode * inode;
        struct dentry * root;
 
+       lock_kernel();
+
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = DLMFS_MAGIC;
        sb->s_op = &dlmfs_ops;
        inode = dlmfs_get_root_inode(sb);
-       if (!inode)
+       if (!inode) {
+               unlock_kernel();
                return -ENOMEM;
+       }
 
        root = d_alloc_root(inode);
        if (!root) {
                iput(inode);
+               unlock_kernel();
                return -ENOMEM;
        }
        sb->s_root = root;
+       unlock_kernel();
        return 0;
 }
 
 
        char nodestr[8];
        struct ocfs2_blockcheck_stats stats;
 
+       lock_kernel();
+
        mlog_entry("%p, %p, %i", sb, data, silent);
 
        if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) {
                        atomic_set(&osb->vol_state, VOLUME_DISABLED);
                        wake_up(&osb->osb_mount_event);
                        mlog_exit(status);
+                       unlock_kernel();
                        return status;
                }
        }
        ocfs2_orphan_scan_start(osb);
 
        mlog_exit(status);
+       unlock_kernel();
        return status;
 
 read_super_error:
        }
 
        mlog_exit(status);
+       unlock_kernel();
        return status;
 }
 
 
        struct qnx4_sb_info *qs;
        int ret = -EINVAL;
 
+       lock_kernel();
+
        qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
-       if (!qs)
+       if (!qs) {
+               unlock_kernel();
                return -ENOMEM;
+       }
        s->s_fs_info = qs;
 
        sb_set_blocksize(s, QNX4_BLOCK_SIZE);
 
        brelse(bh);
 
+       unlock_kernel();
        return 0;
 
       outi:
       outnobh:
        kfree(qs);
        s->s_fs_info = NULL;
+       unlock_kernel();
        return ret;
 }
 
 
        void *mem;
        static int warn_count;
 
+       lock_kernel();
+
        if (warn_count < 5) {
                warn_count++;
                printk(KERN_EMERG "smbfs is deprecated and will be removed"
 
        smb_new_dentry(sb->s_root);
 
+       unlock_kernel();
        return 0;
 
 out_no_root:
 out_no_data:
        printk(KERN_ERR "smb_fill_super: missing data argument\n");
 out_fail:
+       unlock_kernel();
        return -EINVAL;
 out_no_server:
        printk(KERN_ERR "smb_fill_super: cannot allocate struct smb_sb_info\n");
+       unlock_kernel();
        return -ENOMEM;
 }
 
 
        u64 lookup_table_start, xattr_id_table_start;
        int err;
 
+       lock_kernel();
+
        TRACE("Entered squashfs_fill_superblock\n");
 
        sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL);
        if (sb->s_fs_info == NULL) {
                ERROR("Failed to allocate squashfs_sb_info\n");
+               unlock_kernel();
                return -ENOMEM;
        }
        msblk = sb->s_fs_info;
 
        TRACE("Leaving squashfs_fill_super\n");
        kfree(sblk);
+       unlock_kernel();
        return 0;
 
 failed_mount:
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
        kfree(sblk);
+       unlock_kernel();
        return err;
 
 failure:
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
+       unlock_kernel();
        return -ENOMEM;
 }
 
 
        struct kernel_lb_addr rootdir, fileset;
        struct udf_sb_info *sbi;
 
+       lock_kernel();
+
        uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
        uopt.uid = -1;
        uopt.gid = -1;
        uopt.dmode = UDF_INVALID_MODE;
 
        sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
-       if (!sbi)
+       if (!sbi) {
+               unlock_kernel();
                return -ENOMEM;
+       }
 
        sb->s_fs_info = sbi;
 
                goto error_out;
        }
        sb->s_maxbytes = MAX_LFS_FILESIZE;
+       unlock_kernel();
        return 0;
 
 error_out:
        kfree(sbi);
        sb->s_fs_info = NULL;
 
+       unlock_kernel();
        return -EINVAL;
 }
 
 
        unsigned maxsymlen;
        int ret = -EINVAL;
 
+       lock_kernel();
+
        uspi = NULL;
        ubh = NULL;
        flags = 0;
                        goto failed;
 
        UFSD("EXIT\n");
+       unlock_kernel();
        return 0;
 
 dalloc_failed:
        kfree(sbi);
        sb->s_fs_info = NULL;
        UFSD("EXIT (FAILED)\n");
+       unlock_kernel();
        return ret;
 
 failed_nomem:
        UFSD("EXIT (NOMEM)\n");
+       unlock_kernel();
        return -ENOMEM;
 }
 
 
        struct super_block *sb;
        struct cgroupfs_root *new_root;
 
+       lock_kernel();
+
        /* First find the desired set of subsystems */
        mutex_lock(&cgroup_mutex);
        ret = parse_cgroupfs_options(data, &opts);
        simple_set_mnt(mnt, sb);
        kfree(opts.release_agent);
        kfree(opts.name);
+       unlock_kernel();
        return 0;
 
  drop_new_super:
  out_err:
        kfree(opts.release_agent);
        kfree(opts.name);
+       unlock_kernel();
 
        return ret;
 }