[Final call for testers][PATCH] superblock handling changes (2.4.6-pre3)

Alexander Viro (viro@math.psu.edu)
Fri, 15 Jun 2001 01:10:00 -0400 (EDT)


> > Please, be careful with that one. _If_ it blows up it's more than
> > likely to leave box in a state when any activity on sync/mount/umount
> > stops dead. It is pretty straightforward (in split state) and I believe
> > that if there are bugs they will be easy to find, but until then...
> > Reviewing the code should be completely safe, though ;-) Seriously, I
> > think that it's OK, but I've missed one in it, so no warranties.
> >
> > If it gets no complaints in a reasonable time I'm going to
> > resubmit it to Linus, so... Please, help testing it. And yes, I'll
> > keep torturing it myself (obviously).

Folks, this is the final call for testers. If no bug reports show up
I'm going to submit the patch in question (in split form) to Linus next
evening.

BTW, especially brave souls are welcome to extended patchset - this patch
corresponds to first 8 chunks. The rest mostly completes the locking changes
in superblock handling and kills get_super() races for good. Description
of the patches (and patches themselves) can be found on
ftp.math.psu.edu/pub/viro, in Description-S6-pre3, [0-7]*S6-pre3 and
B[0-9]*-S6-pre3 resp. Code review and comments are more then welcome.

diff -urN S6-pre3/arch/parisc/hpux/sys_hpux.c S6-pre3-get_super/arch/parisc/hpux/sys_hpux.c
--- S6-pre3/arch/parisc/hpux/sys_hpux.c Fri Feb 16 20:46:44 2001
+++ S6-pre3-get_super/arch/parisc/hpux/sys_hpux.c Wed Jun 13 00:27:52 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-pre3/fs/block_dev.c S6-pre3-get_super/fs/block_dev.c
--- S6-pre3/fs/block_dev.c Tue Jun 12 21:42:37 2001
+++ S6-pre3-get_super/fs/block_dev.c Wed Jun 13 00:25:21 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-pre3/fs/buffer.c S6-pre3-get_super/fs/buffer.c
--- S6-pre3/fs/buffer.c Tue Jun 12 21:42:37 2001
+++ S6-pre3-get_super/fs/buffer.c Wed Jun 13 00:25:21 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-pre3/fs/dquot.c S6-pre3-get_super/fs/dquot.c
--- S6-pre3/fs/dquot.c Tue Jun 12 21:42:37 2001
+++ S6-pre3-get_super/fs/dquot.c Wed Jun 13 00:27:52 2001
@@ -1597,6 +1597,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-pre3/fs/inode.c S6-pre3-get_super/fs/inode.c
--- S6-pre3/fs/inode.c Tue Jun 12 21:42:37 2001
+++ S6-pre3-get_super/fs/inode.c Wed Jun 13 00:35:20 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,61 +302,96 @@
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);
}

+/*
+ * 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);
+}
+
+/*
+ * 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) {
+ drop_super(s);
+ 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 = sb_entry(super_blocks.next);
+ struct super_block * s;

/*
* Search the super_blocks array for the device(s) to sync.
*/
- 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;
- 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) {
+ sync_inodes_sb(s);
+ drop_super(s);
+ }
+ } else {
+ while ((s = get_super_to_sync()) != NULL) {
+ sync_inodes_sb(s);
+ drop_super(s);
}
- up_read(&sb->s_umount);
- if (dev)
- break;
}
}

@@ -382,13 +400,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);
}

/**
@@ -598,15 +622,18 @@

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;
- if (sb)
+ sb = get_super(dev);
+ if (sb) {
res = invalidate_inodes(sb);
+ drop_super(sb);
+ }
invalidate_buffers(dev);
return res;
}
diff -urN S6-pre3/fs/super.c S6-pre3-get_super/fs/super.c
--- S6-pre3/fs/super.c Tue Jun 12 21:42:38 2001
+++ S6-pre3-get_super/fs/super.c Wed Jun 13 00:35:20 2001
@@ -59,9 +59,8 @@
/* 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;

/*
* Handling of filesystem drivers list.
@@ -386,7 +385,6 @@
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);
if (sb->s_type->fs_flags & FS_SINGLE)
@@ -395,10 +393,11 @@
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 +407,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,16 +484,12 @@
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);
kill_super(sb);
}

-
/* Use octal escapes, like mount does, for embedded spaces etc. */
static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };

@@ -645,6 +638,49 @@
#undef MANGLE
#undef FREEROOM
}
+
+static inline void __put_super(struct super_block *sb)
+{
+ spin_lock(&sb_lock);
+ if (!--sb->s_count)
+ kfree(sb);
+ 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);
+}
+
+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
@@ -655,21 +691,29 @@
{
struct super_block * sb;

- 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;
- 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);
+ if (dev) {
+ sb = get_super(dev);
+ if (sb) {
+ if (sb->s_dirt)
+ write_super(sb);
+ drop_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);
+ drop_super(sb);
+ goto restart;
+ } else
+ sb = sb_entry(sb->s_list.next);
+ spin_unlock(&sb_lock);
}

/**
@@ -687,17 +731,21 @@
if (!dev)
return NULL;
restart:
- 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... */
- lock_super(s);
- unlock_super(s);
- if (s->s_dev == dev)
- return s;
- goto restart;
- } else
- s = sb_entry(s->s_list.next);
+ spin_lock(&sb_lock);
+ 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;
}

@@ -714,6 +762,7 @@
if (s == NULL)
goto out;
err = vfs_statfs(s, &sbuf);
+ drop_super(s);
if (err)
goto out;

@@ -735,35 +784,23 @@
* the request.
*/

-static struct super_block *get_empty_super(void)
+static struct super_block *alloc_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;
- return 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);
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);
+ 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);
+ s->s_maxbytes = MAX_NON_LFS;
}
return s;
}
@@ -773,16 +810,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;
@@ -798,6 +835,11 @@
s->s_bdev = 0;
s->s_type = NULL;
unlock_super(s);
+ atomic_dec(&s->s_active);
+ spin_lock(&sb_lock);
+ list_del(&s->s_list);
+ spin_unlock(&sb_lock);
+ __put_super(s);
return NULL;
}

@@ -863,9 +905,25 @@
if (sb) {
if (fs_type == sb->s_type &&
((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
+/*
+ * 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);
+ up_read(&sb->s_umount);
path_release(&nd);
return sb;
}
+ drop_super(sb);
} else {
mode_t mode = FMODE_READ; /* we always need it ;-) */
if (!(flags & MS_RDONLY))
@@ -926,6 +984,7 @@
sb = fs_type->kern_mnt->mnt_sb;
if (!sb)
BUG();
+ atomic_inc(&sb->s_active);
do_remount_sb(sb, flags, data);
return sb;
}
@@ -938,12 +997,8 @@
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);
+ if (!atomic_dec_and_test(&sb->s_active))
return;
- }
- spin_unlock(&dcache_lock);
down_write(&sb->s_umount);
lock_kernel();
sb->s_root = NULL;
@@ -975,12 +1030,15 @@
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);
+ spin_lock(&sb_lock);
+ list_del(&sb->s_list);
+ spin_unlock(&sb_lock);
+ put_super(sb);
}

/*
@@ -1045,9 +1103,6 @@
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);
type->kern_mnt = mnt;
return mnt;
}
@@ -1092,7 +1147,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 +1379,6 @@
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);

/* Something was mounted here while we slept */
while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
@@ -1583,7 +1635,10 @@
check_disk_change(ROOT_DEV);
sb = get_super(ROOT_DEV);
if (sb) {
+ /* FIXME */
fs_type = sb->s_type;
+ atomic_inc(&sb->s_active);
+ up_read(&sb->s_umount);
goto mount_it;
}

diff -urN S6-pre3/include/linux/fs.h S6-pre3-get_super/include/linux/fs.h
--- S6-pre3/include/linux/fs.h Tue Jun 12 21:42:39 2001
+++ S6-pre3-get_super/include/linux/fs.h Wed Jun 13 00:32:04 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 */
@@ -662,6 +661,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,13 +679,14 @@
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 */
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 {
@@ -1147,6 +1148,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 *);
@@ -1344,11 +1346,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-pre3/include/linux/mount.h S6-pre3-get_super/include/linux/mount.h
--- S6-pre3/include/linux/mount.h Tue Jun 12 21:42:39 2001
+++ S6-pre3-get_super/include/linux/mount.h Wed Jun 13 00:23:46 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 */
diff -urN S6-pre3/kernel/ksyms.c S6-pre3-get_super/kernel/ksyms.c
--- S6-pre3/kernel/ksyms.c Tue Jun 12 21:42:39 2001
+++ S6-pre3-get_super/kernel/ksyms.c Wed Jun 13 00:27:52 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);
diff -urN S6-pre3/kernel/sysctl.c S6-pre3-get_super/kernel/sysctl.c
--- S6-pre3/kernel/sysctl.c Sat Apr 14 21:41:29 2001
+++ S6-pre3-get_super/kernel/sysctl.c Wed Jun 13 00:32:04 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),

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/