* [PATCH] fs/super.c fixes (1/8)
@ 2001-08-09 23:30 Alexander Viro
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (2/8) Alexander Viro
0 siblings, 1 reply; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:30 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Linus, I'm resubmitting this stuff - it got a lot of local testing
plus public one in -ac. It's split in 8 chunks, so that will be 8 sepatate
mails (each with patch description). I hope each of them is small and
obvious enough. Patches are incremental to each other and start at 2.4.8-pre7.
Please, apply.
Part 1/8:
->mnt_instances/->s_mounts list is gone. It is replaced by ->s_active - amount
of vfsmounts over given superblock. All accesses are under mount_sem right
now.
diff -urN S8-pre7/fs/super.c S8-pre7-mnt_instances/fs/super.c
--- S8-pre7/fs/super.c Tue Jul 3 21:09:13 2001
+++ S8-pre7-mnt_instances/fs/super.c Thu Aug 9 19:07:31 2001
@@ -386,19 +386,20 @@
mnt->mnt_parent = mnt;
spin_lock(&dcache_lock);
- list_add(&mnt->mnt_instances, &sb->s_mounts);
list_add(&mnt->mnt_list, vfsmntlist.prev);
spin_unlock(&dcache_lock);
+ atomic_inc(&sb->s_active);
if (sb->s_type->fs_flags & FS_SINGLE)
get_filesystem(sb->s_type);
out:
return mnt;
}
-static struct vfsmount *clone_mnt(struct vfsmount *old_mnt, struct dentry *root)
+static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)
{
- char *name = old_mnt->mnt_devname;
+ char *name = old->mnt_devname;
struct vfsmount *mnt = alloc_vfsmnt();
+ struct super_block *sb = old->mnt_sb;
if (!mnt)
goto out;
@@ -408,14 +409,12 @@
if (mnt->mnt_devname)
strcpy(mnt->mnt_devname, name);
}
- mnt->mnt_sb = old_mnt->mnt_sb;
+ mnt->mnt_sb = sb;
mnt->mnt_root = dget(root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- spin_lock(&dcache_lock);
- list_add(&mnt->mnt_instances, &old_mnt->mnt_instances);
- spin_unlock(&dcache_lock);
+ atomic_inc(&sb->s_active);
out:
return mnt;
}
@@ -487,9 +486,6 @@
struct super_block *sb = mnt->mnt_sb;
dput(mnt->mnt_root);
- spin_lock(&dcache_lock);
- list_del(&mnt->mnt_instances);
- spin_unlock(&dcache_lock);
if (mnt->mnt_devname)
kfree(mnt->mnt_devname);
kmem_cache_free(mnt_cache, mnt);
@@ -757,9 +753,9 @@
INIT_LIST_HEAD(&s->s_locked_inodes);
list_add (&s->s_list, super_blocks.prev);
INIT_LIST_HEAD(&s->s_files);
- INIT_LIST_HEAD(&s->s_mounts);
init_rwsem(&s->s_umount);
sema_init(&s->s_lock, 1);
+ atomic_set(&s->s_active, 0);
sema_init(&s->s_vfs_rename_sem,1);
sema_init(&s->s_nfsd_free_path_sem,1);
sema_init(&s->s_dquot.dqio_sem, 1);
@@ -938,12 +934,9 @@
struct file_system_type *fs = sb->s_type;
struct super_operations *sop = sb->s_op;
- spin_lock(&dcache_lock);
- if (!list_empty(&sb->s_mounts)) {
- spin_unlock(&dcache_lock);
+ atomic_dec(&sb->s_active);
+ if (atomic_read(&sb->s_active))
return;
- }
- spin_unlock(&dcache_lock);
down_write(&sb->s_umount);
lock_kernel();
sb->s_root = NULL;
@@ -1045,9 +1038,7 @@
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- spin_lock(&dcache_lock);
- list_add(&mnt->mnt_instances, &sb->s_mounts);
- spin_unlock(&dcache_lock);
+ atomic_inc(&sb->s_active);
type->kern_mnt = mnt;
return mnt;
}
@@ -1092,7 +1083,7 @@
spin_lock(&dcache_lock);
- if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
+ if (atomic_read(&sb->s_active) > 1) {
if (atomic_read(&mnt->mnt_count) > 2) {
spin_unlock(&dcache_lock);
return -EBUSY;
@@ -1324,9 +1315,7 @@
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- spin_lock(&dcache_lock);
- list_add(&mnt->mnt_instances, &sb->s_mounts);
- spin_unlock(&dcache_lock);
+ atomic_inc(&sb->s_active);
/* Something was mounted here while we slept */
while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
diff -urN S8-pre7/include/linux/fs.h S8-pre7-mnt_instances/include/linux/fs.h
--- S8-pre7/include/linux/fs.h Wed Aug 8 17:54:56 2001
+++ S8-pre7-mnt_instances/include/linux/fs.h Thu Aug 9 19:07:31 2001
@@ -680,13 +680,13 @@
struct dentry *s_root;
struct rw_semaphore s_umount;
struct semaphore s_lock;
+ atomic_t s_active;
struct list_head s_dirty; /* dirty inodes */
struct list_head s_locked_inodes;/* inodes being synced */
struct list_head s_files;
struct block_device *s_bdev;
- struct list_head s_mounts; /* vfsmount(s) of this one */
struct quota_mount_options s_dquot; /* Diskquota specific options */
union {
diff -urN S8-pre7/include/linux/mount.h S8-pre7-mnt_instances/include/linux/mount.h
--- S8-pre7/include/linux/mount.h Tue Jul 3 21:09:14 2001
+++ S8-pre7-mnt_instances/include/linux/mount.h Thu Aug 9 19:07:31 2001
@@ -18,7 +18,6 @@
struct vfsmount *mnt_parent; /* fs we are mounted on */
struct dentry *mnt_mountpoint; /* dentry of mountpoint */
struct dentry *mnt_root; /* root of the mounted tree */
- struct list_head mnt_instances; /* other vfsmounts of the same fs */
struct super_block *mnt_sb; /* pointer to superblock */
struct list_head mnt_mounts; /* list of children, anchored here */
struct list_head mnt_child; /* and going through their mnt_child */
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (2/8)
2001-08-09 23:30 [PATCH] fs/super.c fixes (1/8) Alexander Viro
@ 2001-08-09 23:31 ` Alexander Viro
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (3/8) Alexander Viro
0 siblings, 1 reply; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:31 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 2/8:
incrementing ->s_active is pulled from do_add_mount() into get_sb_...() and
further into read_super() and get_empty_super(). All that shifting is within
mount_sem exclusion areas, so it's an equivalent transformation (see above).
diff -urN S8-pre7-mnt_instances/fs/super.c S8-pre7-s_active/fs/super.c
--- S8-pre7-mnt_instances/fs/super.c Thu Aug 9 19:07:31 2001
+++ S8-pre7-s_active/fs/super.c Thu Aug 9 19:07:31 2001
@@ -388,7 +388,6 @@
spin_lock(&dcache_lock);
list_add(&mnt->mnt_list, vfsmntlist.prev);
spin_unlock(&dcache_lock);
- atomic_inc(&sb->s_active);
if (sb->s_type->fs_flags & FS_SINGLE)
get_filesystem(sb->s_type);
out:
@@ -740,6 +739,7 @@
s = sb_entry(s->s_list.next)) {
if (s->s_dev)
continue;
+ atomic_inc(&s->s_active);
return s;
}
/* Need a new one... */
@@ -755,7 +755,7 @@
INIT_LIST_HEAD(&s->s_files);
init_rwsem(&s->s_umount);
sema_init(&s->s_lock, 1);
- atomic_set(&s->s_active, 0);
+ atomic_set(&s->s_active, 1);
sema_init(&s->s_vfs_rename_sem,1);
sema_init(&s->s_nfsd_free_path_sem,1);
sema_init(&s->s_dquot.dqio_sem, 1);
@@ -794,6 +794,7 @@
s->s_bdev = 0;
s->s_type = NULL;
unlock_super(s);
+ atomic_dec(&s->s_active);
return NULL;
}
@@ -860,6 +861,7 @@
if (fs_type == sb->s_type &&
((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
path_release(&nd);
+ atomic_inc(&sb->s_active);
return sb;
}
} else {
@@ -923,6 +925,7 @@
if (!sb)
BUG();
do_remount_sb(sb, flags, data);
+ atomic_inc(&sb->s_active);
return sb;
}
@@ -1038,7 +1041,6 @@
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- atomic_inc(&sb->s_active);
type->kern_mnt = mnt;
return mnt;
}
@@ -1315,7 +1317,6 @@
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- atomic_inc(&sb->s_active);
/* Something was mounted here while we slept */
while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
@@ -1573,6 +1574,7 @@
sb = get_super(ROOT_DEV);
if (sb) {
fs_type = sb->s_type;
+ atomic_inc(&sb->s_active);
goto mount_it;
}
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (3/8)
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (2/8) Alexander Viro
@ 2001-08-09 23:31 ` Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (4/8) Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (5/8) Alexander Viro
0 siblings, 2 replies; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:31 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 3/8:
blkdev_put(bdev, BDEV_FS) is always called when superblock is already
dead. No point trying to sync fs structures - they are gone at that
point. So instead of fsync_dev() we call fsync_no_super() - fsync_dev()
sans the sync_inodes()/sync_supers() calls. That allows to shift releasing
->s_umount to the very end of kill_super().
diff -urN S8-pre7-s_active/fs/block_dev.c S8-pre7-fsync_no_super/fs/block_dev.c
--- S8-pre7-s_active/fs/block_dev.c Tue Jul 3 21:09:13 2001
+++ S8-pre7-fsync_no_super/fs/block_dev.c Thu Aug 9 19:07:31 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 S8-pre7-s_active/fs/buffer.c S8-pre7-fsync_no_super/fs/buffer.c
--- S8-pre7-s_active/fs/buffer.c Wed Aug 8 17:54:55 2001
+++ S8-pre7-fsync_no_super/fs/buffer.c Thu Aug 9 19:07:31 2001
@@ -346,6 +346,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 S8-pre7-s_active/fs/super.c S8-pre7-fsync_no_super/fs/super.c
--- S8-pre7-s_active/fs/super.c Thu Aug 9 19:07:31 2001
+++ S8-pre7-fsync_no_super/fs/super.c Thu Aug 9 19:07:31 2001
@@ -971,12 +971,12 @@
sb->s_type = NULL;
unlock_super(sb);
unlock_kernel();
- up_write(&sb->s_umount);
if (bdev) {
blkdev_put(bdev, BDEV_FS);
bdput(bdev);
} else
put_unnamed_dev(dev);
+ up_write(&sb->s_umount);
}
/*
diff -urN S8-pre7-s_active/include/linux/fs.h S8-pre7-fsync_no_super/include/linux/fs.h
--- S8-pre7-s_active/include/linux/fs.h Thu Aug 9 19:07:31 2001
+++ S8-pre7-fsync_no_super/include/linux/fs.h Thu Aug 9 19:07:31 2001
@@ -1161,6 +1161,7 @@
extern void sync_dev(kdev_t);
extern int fsync_dev(kdev_t);
extern int fsync_super(struct super_block *);
+extern int fsync_no_super(kdev_t);
extern void sync_inodes_sb(struct super_block *);
extern int fsync_inode_buffers(struct inode *);
extern int osync_inode_buffers(struct inode *);
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (4/8)
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (3/8) Alexander Viro
@ 2001-08-09 23:32 ` Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (5/8) Alexander Viro
1 sibling, 0 replies; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:32 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 4/8:
Preparation to refcounting - calls of get_super() are followed by
drop_super(). Right now it's empty, that will be changed on the next
step. For now we simply put the calls in right places.
diff -urN S8-pre7-fsync_no_super/arch/parisc/hpux/sys_hpux.c S8-pre7-drop_super/arch/parisc/hpux/sys_hpux.c
--- S8-pre7-fsync_no_super/arch/parisc/hpux/sys_hpux.c Fri Feb 16 20:46:44 2001
+++ S8-pre7-drop_super/arch/parisc/hpux/sys_hpux.c Thu Aug 9 19:07:31 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 S8-pre7-fsync_no_super/fs/dquot.c S8-pre7-drop_super/fs/dquot.c
--- S8-pre7-fsync_no_super/fs/dquot.c Sun Jul 29 01:54:47 2001
+++ S8-pre7-drop_super/fs/dquot.c Thu Aug 9 19:07:31 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 S8-pre7-fsync_no_super/fs/inode.c S8-pre7-drop_super/fs/inode.c
--- S8-pre7-fsync_no_super/fs/inode.c Wed Aug 8 17:54:55 2001
+++ S8-pre7-drop_super/fs/inode.c Thu Aug 9 19:07:32 2001
@@ -605,8 +605,10 @@
fsync_dev(dev);
res = 0;
- if (sb)
+ if (sb) {
res = invalidate_inodes(sb);
+ drop_super(sb);
+ }
invalidate_buffers(dev);
return res;
}
diff -urN S8-pre7-fsync_no_super/fs/super.c S8-pre7-drop_super/fs/super.c
--- S8-pre7-fsync_no_super/fs/super.c Thu Aug 9 19:07:31 2001
+++ S8-pre7-drop_super/fs/super.c Thu Aug 9 19:07:32 2001
@@ -491,7 +491,6 @@
kill_super(sb);
}
-
/* Use octal escapes, like mount does, for embedded spaces etc. */
static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
@@ -640,6 +639,10 @@
#undef MANGLE
#undef FREEROOM
}
+
+void drop_super(struct super_block *sb)
+{
+}
/*
* Note: check the dirty flag before waiting, so we don't
@@ -709,6 +712,7 @@
if (s == NULL)
goto out;
err = vfs_statfs(s, &sbuf);
+ drop_super(s);
if (err)
goto out;
diff -urN S8-pre7-fsync_no_super/include/linux/fs.h S8-pre7-drop_super/include/linux/fs.h
--- S8-pre7-fsync_no_super/include/linux/fs.h Thu Aug 9 19:07:31 2001
+++ S8-pre7-drop_super/include/linux/fs.h Thu Aug 9 19:07:32 2001
@@ -1359,11 +1359,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 S8-pre7-fsync_no_super/kernel/ksyms.c S8-pre7-drop_super/kernel/ksyms.c
--- S8-pre7-fsync_no_super/kernel/ksyms.c Wed Aug 8 17:54:57 2001
+++ S8-pre7-drop_super/kernel/ksyms.c Thu Aug 9 19:07:32 2001
@@ -128,6 +128,7 @@
EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(get_super);
+EXPORT_SYMBOL(drop_super);
EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(names_cachep);
EXPORT_SYMBOL(fput);
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (5/8)
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (3/8) Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (4/8) Alexander Viro
@ 2001-08-09 23:32 ` Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (6/8) Alexander Viro
1 sibling, 1 reply; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:32 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 5/8:
super_blocks list is protected by new spinlock (sb_lock). It is taken after
all other locks. We also add the second counter to struct super_block -
scheme is similar to mm_struct handling (there will be one difference,
but that will wait until much later).
Current rules for s_count:
* all accesses are protected by sb_lock.
* all "permanent" references (vfsmount ones) are lumped together.
Temporary ones are counted separately.
At that stage we don't use s_count - only maintain its value.
Note: converting temporary reference into permanent one (that happens
in get_sb_bdev() when we decide to return an already mounted superblock
from the same device) is actually tricky. That's the place where our
situation differs from mm_struct one. Right now we simply rely on mount_sem.
diff -urN S8-pre7-drop_super/fs/inode.c S8-pre7-s_count/fs/inode.c
--- S8-pre7-drop_super/fs/inode.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-s_count/fs/inode.c Thu Aug 9 19:07:32 2001
@@ -339,30 +339,48 @@
spin_unlock(&inode_lock);
}
+/*
+ * Note:
+ * We don't need to grab a reference to superblock here. If it has non-empty
+ * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
+ * past sync_inodes_sb() until both ->s_dirty and ->s_locked_inodes are
+ * empty. Since __sync_one() regains inode_lock before it finally moves
+ * inode from superblock lists we are OK.
+ */
+
void sync_unlocked_inodes(void)
{
- struct super_block * sb = sb_entry(super_blocks.next);
+ struct super_block * sb;
+ spin_lock(&inode_lock);
+ spin_lock(&sb_lock);
+ sb = sb_entry(super_blocks.next);
for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
if (!list_empty(&sb->s_dirty)) {
- spin_lock(&inode_lock);
+ spin_unlock(&sb_lock);
sync_list(&sb->s_dirty);
- spin_unlock(&inode_lock);
+ spin_lock(&sb_lock);
}
}
+ spin_unlock(&sb_lock);
+ spin_unlock(&inode_lock);
}
void sync_inodes(kdev_t dev)
{
- struct super_block * sb = sb_entry(super_blocks.next);
+ struct super_block * sb;
/*
* Search the super_blocks array for the device(s) to sync.
*/
+ spin_lock(&sb_lock);
+ sb = sb_entry(super_blocks.next);
for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
if (!sb->s_dev)
continue;
if (dev && sb->s_dev != dev)
continue;
+ sb->s_count++;
+ spin_unlock(&sb_lock);
down_read(&sb->s_umount);
if (sb->s_dev && (sb->s_dev == dev || !dev)) {
spin_lock(&inode_lock);
@@ -372,9 +390,12 @@
spin_unlock(&inode_lock);
}
up_read(&sb->s_umount);
+ spin_lock(&sb_lock);
+ sb->s_count--;
if (dev)
break;
}
+ spin_unlock(&sb_lock);
}
/*
@@ -382,13 +403,19 @@
*/
static void try_to_sync_unused_inodes(void)
{
- struct super_block * sb = sb_entry(super_blocks.next);
+ struct super_block * sb;
+
+ spin_lock(&sb_lock);
+ sb = sb_entry(super_blocks.next);
for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
if (!sb->s_dev)
continue;
+ spin_unlock(&sb_lock);
if (!try_to_sync_unused_list(&sb->s_dirty))
- break;
+ return;
+ spin_lock(&sb_lock);
}
+ spin_unlock(&sb_lock);
}
/**
diff -urN S8-pre7-drop_super/fs/super.c S8-pre7-s_count/fs/super.c
--- S8-pre7-drop_super/fs/super.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-s_count/fs/super.c Thu Aug 9 19:07:32 2001
@@ -62,6 +62,7 @@
int nr_super_blocks;
int max_super_blocks = NR_SUPER;
LIST_HEAD(super_blocks);
+spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
/*
* Handling of filesystem drivers list.
@@ -640,8 +641,16 @@
#undef FREEROOM
}
+static inline void __put_super(struct super_block *sb)
+{
+ spin_lock(&sb_lock);
+ sb->s_count--;
+ spin_unlock(&sb_lock);
+}
+
void drop_super(struct super_block *sb)
{
+ __put_super(sb);
}
/*
@@ -653,6 +662,7 @@
{
struct super_block * sb;
+ spin_lock(&sb_lock);
for (sb = sb_entry(super_blocks.next);
sb != sb_entry(&super_blocks);
sb = sb_entry(sb->s_list.next)) {
@@ -662,12 +672,17 @@
continue;
if (!sb->s_dirt)
continue;
+ sb->s_count++;
+ spin_unlock(&sb_lock);
lock_super(sb);
if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev))
if (sb->s_op && sb->s_op->write_super)
sb->s_op->write_super(sb);
unlock_super(sb);
+ spin_lock(&sb_lock);
+ sb->s_count--;
}
+ spin_unlock(&sb_lock);
}
/**
@@ -685,17 +700,23 @@
if (!dev)
return NULL;
restart:
+ spin_lock(&sb_lock);
s = sb_entry(super_blocks.next);
while (s != sb_entry(&super_blocks))
if (s->s_dev == dev) {
/* Yes, it sucks. As soon as we get refcounting... */
+ /* Almost there */
+ s->s_count++;
+ spin_unlock(&sb_lock);
lock_super(s);
unlock_super(s);
if (s->s_dev == dev)
return s;
+ drop_super(s);
goto restart;
} else
s = sb_entry(s->s_list.next);
+ spin_unlock(&sb_lock);
return NULL;
}
@@ -738,14 +759,18 @@
{
struct super_block *s;
+ spin_lock(&sb_lock);
for (s = sb_entry(super_blocks.next);
s != sb_entry(&super_blocks);
s = sb_entry(s->s_list.next)) {
if (s->s_dev)
continue;
+ s->s_count++;
atomic_inc(&s->s_active);
+ spin_unlock(&sb_lock);
return s;
}
+ spin_unlock(&sb_lock);
/* Need a new one... */
if (nr_super_blocks >= max_super_blocks)
return NULL;
@@ -753,6 +778,7 @@
if (s) {
nr_super_blocks++;
memset(s, 0, sizeof(struct super_block));
+ spin_lock(&sb_lock);
INIT_LIST_HEAD(&s->s_dirty);
INIT_LIST_HEAD(&s->s_locked_inodes);
list_add (&s->s_list, super_blocks.prev);
@@ -760,10 +786,12 @@
init_rwsem(&s->s_umount);
sema_init(&s->s_lock, 1);
atomic_set(&s->s_active, 1);
+ s->s_count = 1;
sema_init(&s->s_vfs_rename_sem,1);
sema_init(&s->s_nfsd_free_path_sem,1);
sema_init(&s->s_dquot.dqio_sem, 1);
sema_init(&s->s_dquot.dqoff_sem, 1);
+ spin_unlock(&sb_lock);
}
return s;
}
@@ -799,6 +827,7 @@
s->s_type = NULL;
unlock_super(s);
atomic_dec(&s->s_active);
+ __put_super(s);
return NULL;
}
@@ -864,10 +893,24 @@
if (sb) {
if (fs_type == sb->s_type &&
((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
- path_release(&nd);
+/*
+ * We are heavily relying on mount_sem here. We _will_ get rid of that
+ * ugliness RSN (and then atomicity of ->s_active will play), but first
+ * we need to get rid of "reuse" branch of get_empty_super() and that
+ * requires reference counters. Chicken and egg problem, but fortunately
+ * we can use the fact that right now all accesses to ->s_active are
+ * under mount_sem.
+ */
+ if (atomic_read(&sb->s_active)) {
+ spin_lock(&sb_lock);
+ sb->s_count--;
+ spin_unlock(&sb_lock);
+ }
atomic_inc(&sb->s_active);
+ path_release(&nd);
return sb;
}
+ __put_super(sb);
} else {
mode_t mode = FMODE_READ; /* we always need it ;-) */
if (!(flags & MS_RDONLY))
@@ -941,8 +984,7 @@
struct file_system_type *fs = sb->s_type;
struct super_operations *sop = sb->s_op;
- atomic_dec(&sb->s_active);
- if (atomic_read(&sb->s_active))
+ if (!atomic_dec_and_test(&sb->s_active))
return;
down_write(&sb->s_umount);
lock_kernel();
@@ -981,6 +1023,7 @@
} else
put_unnamed_dev(dev);
up_write(&sb->s_umount);
+ __put_super(sb);
}
/*
@@ -1577,6 +1620,7 @@
check_disk_change(ROOT_DEV);
sb = get_super(ROOT_DEV);
if (sb) {
+ /* FIXME */
fs_type = sb->s_type;
atomic_inc(&sb->s_active);
goto mount_it;
diff -urN S8-pre7-drop_super/include/linux/fs.h S8-pre7-s_count/include/linux/fs.h
--- S8-pre7-drop_super/include/linux/fs.h Thu Aug 9 19:07:32 2001
+++ S8-pre7-s_count/include/linux/fs.h Thu Aug 9 19:07:32 2001
@@ -663,6 +663,7 @@
#include <linux/cramfs_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 {
@@ -680,6 +681,7 @@
struct dentry *s_root;
struct rw_semaphore s_umount;
struct semaphore s_lock;
+ int s_count;
atomic_t s_active;
struct list_head s_dirty; /* dirty inodes */
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (6/8)
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (5/8) Alexander Viro
@ 2001-08-09 23:32 ` Alexander Viro
2001-08-09 23:33 ` [PATCH] fs/super.c fixes (7/8) Alexander Viro
0 siblings, 1 reply; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:32 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 6/8:
OK, that's the first big one.
* we are freeing superblocks when s_count hits zero.
* we are removing superblock from the list when s_active hits zero (at
that point superblock is already doomed).
* functions that used to traverse the list need to restart after
blocking actions. Done.
* sync_inodes_sb() is slightly changed - now it repeats the whole
thing if some of the locked inodes had been dirtied while we were waiting.
As the result, wait_on_dirty() is gone - it's not needed anymore.
* sync_supers() gets shared lock on ->s_umount for the duration of
->write_super(). Since we are already grabbing ->s_lock here it doesn't
add any deadlocks.
diff -urN S8-pre7-s_count/fs/inode.c S8-pre7-freeing/fs/inode.c
--- S8-pre7-s_count/fs/inode.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-freeing/fs/inode.c Thu Aug 9 19:07:32 2001
@@ -258,23 +258,6 @@
__sync_one(list_entry(tmp, struct inode, i_list), 0);
}
-static inline int wait_on_dirty(struct list_head *head)
-{
- struct list_head * tmp;
- list_for_each(tmp, head) {
- struct inode *inode = list_entry(tmp, struct inode, i_list);
- if (!inode->i_state & I_DIRTY)
- continue;
- __iget(inode);
- spin_unlock(&inode_lock);
- __wait_on_inode(inode);
- iput(inode);
- spin_lock(&inode_lock);
- return 1;
- }
- return 0;
-}
-
static inline void wait_on_locked(struct list_head *head)
{
struct list_head * tmp;
@@ -319,23 +302,13 @@
return 1;
}
-/**
- * sync_inodes
- * @dev: device to sync the inodes from.
- *
- * sync_inodes goes through the super block's dirty list,
- * writes them out, and puts them back on the normal list.
- */
-
-/*
- * caller holds exclusive lock on sb->s_umount
- */
-
void sync_inodes_sb(struct super_block *sb)
{
spin_lock(&inode_lock);
- sync_list(&sb->s_dirty);
- wait_on_locked(&sb->s_locked_inodes);
+ while (!list_empty(&sb->s_dirty)||!list_empty(&sb->s_locked_inodes)) {
+ sync_list(&sb->s_dirty);
+ wait_on_locked(&sb->s_locked_inodes);
+ }
spin_unlock(&inode_lock);
}
@@ -365,37 +338,75 @@
spin_unlock(&inode_lock);
}
+/*
+ * Find a superblock with inodes that need to be synced
+ */
+
+static struct super_block *get_super_to_sync(void)
+{
+ struct list_head *p;
+restart:
+ spin_lock(&inode_lock);
+ spin_lock(&sb_lock);
+ list_for_each(p, &super_blocks) {
+ struct super_block *s = list_entry(p,struct super_block,s_list);
+ if (list_empty(&s->s_dirty) && list_empty(&s->s_locked_inodes))
+ continue;
+ s->s_count++;
+ spin_unlock(&sb_lock);
+ spin_unlock(&inode_lock);
+ down_read(&s->s_umount);
+ if (!s->s_root) {
+ up_read(&s->s_umount);
+ spin_lock(&sb_lock);
+ if (!--s->s_count)
+ kfree(s);
+ spin_unlock(&sb_lock);
+ goto restart;
+ }
+ return s;
+ }
+ spin_unlock(&sb_lock);
+ spin_unlock(&inode_lock);
+ return NULL;
+}
+
+/**
+ * sync_inodes
+ * @dev: device to sync the inodes from.
+ *
+ * sync_inodes goes through the super block's dirty list,
+ * writes them out, and puts them back on the normal list.
+ */
+
void sync_inodes(kdev_t dev)
{
- struct super_block * sb;
+ struct super_block * s;
/*
* Search the super_blocks array for the device(s) to sync.
*/
- spin_lock(&sb_lock);
- sb = sb_entry(super_blocks.next);
- for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
- if (!sb->s_dev)
- continue;
- if (dev && sb->s_dev != dev)
- continue;
- sb->s_count++;
- spin_unlock(&sb_lock);
- down_read(&sb->s_umount);
- if (sb->s_dev && (sb->s_dev == dev || !dev)) {
- spin_lock(&inode_lock);
- do {
- sync_list(&sb->s_dirty);
- } while (wait_on_dirty(&sb->s_locked_inodes));
- spin_unlock(&inode_lock);
+ if (dev) {
+ if ((s = get_super(dev)) != NULL) {
+ down_read(&s->s_umount);
+ if (s->s_root)
+ sync_inodes_sb(s);
+ up_read(&s->s_umount);
+ spin_lock(&sb_lock);
+ if (!--s->s_count)
+ kfree(s);
+ spin_unlock(&sb_lock);
+ }
+ } else {
+ while ((s = get_super_to_sync()) != NULL) {
+ sync_inodes_sb(s);
+ up_read(&s->s_umount);
+ spin_lock(&sb_lock);
+ if (!--s->s_count)
+ kfree(s);
+ spin_unlock(&sb_lock);
}
- up_read(&sb->s_umount);
- spin_lock(&sb_lock);
- sb->s_count--;
- if (dev)
- break;
}
- spin_unlock(&sb_lock);
}
/*
diff -urN S8-pre7-s_count/fs/super.c S8-pre7-freeing/fs/super.c
--- S8-pre7-s_count/fs/super.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-freeing/fs/super.c Thu Aug 9 19:07:32 2001
@@ -644,7 +644,8 @@
static inline void __put_super(struct super_block *sb)
{
spin_lock(&sb_lock);
- sb->s_count--;
+ if (!--sb->s_count)
+ kfree(sb);
spin_unlock(&sb_lock);
}
@@ -652,6 +653,21 @@
{
__put_super(sb);
}
+
+static void put_super(struct super_block *sb)
+{
+ up_write(&sb->s_umount);
+ __put_super(sb);
+}
+
+static inline void write_super(struct super_block *sb)
+{
+ lock_super(sb);
+ if (sb->s_root && sb->s_dirt)
+ if (sb->s_op && sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+ unlock_super(sb);
+}
/*
* Note: check the dirty flag before waiting, so we don't
@@ -662,26 +678,30 @@
{
struct super_block * sb;
- spin_lock(&sb_lock);
- for (sb = sb_entry(super_blocks.next);
- sb != sb_entry(&super_blocks);
- sb = sb_entry(sb->s_list.next)) {
- if (!sb->s_dev)
- continue;
- if (dev && sb->s_dev != dev)
- continue;
- if (!sb->s_dirt)
- continue;
- sb->s_count++;
- spin_unlock(&sb_lock);
- lock_super(sb);
- if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev))
- if (sb->s_op && sb->s_op->write_super)
- sb->s_op->write_super(sb);
- unlock_super(sb);
- spin_lock(&sb_lock);
- sb->s_count--;
+ if (dev) {
+ sb = get_super(dev);
+ if (sb) {
+ if (sb->s_dirt)
+ write_super(sb);
+ up_read(&sb->s_umount);
+ __put_super(sb);
+ }
+ return;
}
+restart:
+ spin_lock(&sb_lock);
+ sb = sb_entry(super_blocks.next);
+ while (sb != sb_entry(&super_blocks))
+ if (sb->s_dirt) {
+ sb->s_count++;
+ spin_unlock(&sb_lock);
+ down_read(&sb->s_umount);
+ write_super(sb);
+ up_read(&sb->s_umount);
+ __put_super(sb);
+ goto restart;
+ } else
+ sb = sb_entry(sb->s_list.next);
spin_unlock(&sb_lock);
}
@@ -827,6 +847,9 @@
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;
}
@@ -1022,8 +1045,10 @@
bdput(bdev);
} else
put_unnamed_dev(dev);
- up_write(&sb->s_umount);
- __put_super(sb);
+ spin_lock(&sb_lock);
+ list_del(&sb->s_list);
+ spin_unlock(&sb_lock);
+ put_super(sb);
}
/*
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (7/8)
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (6/8) Alexander Viro
@ 2001-08-09 23:33 ` Alexander Viro
2001-08-09 23:33 ` [PATCH] fs/super.c fixes (8/8) Alexander Viro
0 siblings, 1 reply; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:33 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 7/8:
_Now_ we can drop the "reuse" branch in get_empty_super(). Done, remaining
thing renamed into alloc_super(). Insertion of the allocated superblock into
the super_blocks is moved into the caller (read_super()).
diff -urN S8-pre7-freeing/fs/super.c S8-pre7-alloc_super/fs/super.c
--- S8-pre7-freeing/fs/super.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-alloc_super/fs/super.c Thu Aug 9 19:07:32 2001
@@ -59,8 +59,6 @@
/* this is initialized in init/main.c */
kdev_t ROOT_DEV;
-int nr_super_blocks;
-int max_super_blocks = NR_SUPER;
LIST_HEAD(super_blocks);
spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
@@ -775,43 +773,23 @@
* the request.
*/
-static struct super_block *get_empty_super(void)
+static struct super_block *alloc_super(void)
{
- struct super_block *s;
-
- spin_lock(&sb_lock);
- for (s = sb_entry(super_blocks.next);
- s != sb_entry(&super_blocks);
- s = sb_entry(s->s_list.next)) {
- if (s->s_dev)
- continue;
- s->s_count++;
- atomic_inc(&s->s_active);
- spin_unlock(&sb_lock);
- return s;
- }
- spin_unlock(&sb_lock);
- /* Need a new one... */
- if (nr_super_blocks >= max_super_blocks)
- return NULL;
- s = kmalloc(sizeof(struct super_block), GFP_USER);
+ struct super_block *s = kmalloc(sizeof(struct super_block), GFP_USER);
if (s) {
- nr_super_blocks++;
memset(s, 0, sizeof(struct super_block));
- spin_lock(&sb_lock);
INIT_LIST_HEAD(&s->s_dirty);
INIT_LIST_HEAD(&s->s_locked_inodes);
- list_add (&s->s_list, super_blocks.prev);
INIT_LIST_HEAD(&s->s_files);
init_rwsem(&s->s_umount);
sema_init(&s->s_lock, 1);
- atomic_set(&s->s_active, 1);
s->s_count = 1;
+ atomic_set(&s->s_active, 1);
sema_init(&s->s_vfs_rename_sem,1);
sema_init(&s->s_nfsd_free_path_sem,1);
sema_init(&s->s_dquot.dqio_sem, 1);
sema_init(&s->s_dquot.dqoff_sem, 1);
- spin_unlock(&sb_lock);
+ s->s_maxbytes = MAX_NON_LFS;
}
return s;
}
@@ -821,16 +799,16 @@
void *data, int silent)
{
struct super_block * s;
- s = get_empty_super();
+ s = alloc_super();
if (!s)
goto out;
s->s_dev = dev;
s->s_bdev = bdev;
s->s_flags = flags;
- s->s_dirt = 0;
s->s_type = type;
- s->s_dquot.flags = 0;
- s->s_maxbytes = MAX_NON_LFS;
+ spin_lock(&sb_lock);
+ list_add (&s->s_list, super_blocks.prev);
+ spin_unlock(&sb_lock);
lock_super(s);
if (!type->read_super(s, data, silent))
goto out_fail;
@@ -994,8 +972,8 @@
sb = fs_type->kern_mnt->mnt_sb;
if (!sb)
BUG();
- do_remount_sb(sb, flags, data);
atomic_inc(&sb->s_active);
+ do_remount_sb(sb, flags, data);
return sb;
}
diff -urN S8-pre7-freeing/include/linux/fs.h S8-pre7-alloc_super/include/linux/fs.h
--- S8-pre7-freeing/include/linux/fs.h Thu Aug 9 19:07:32 2001
+++ S8-pre7-alloc_super/include/linux/fs.h Thu Aug 9 19:07:32 2001
@@ -61,7 +61,6 @@
};
extern struct inodes_stat_t inodes_stat;
-extern int max_super_blocks, nr_super_blocks;
extern int leases_enable, dir_notify_enable, lease_break_time;
#define NR_FILE 8192 /* this can well be larger on a larger system */
diff -urN S8-pre7-freeing/kernel/sysctl.c S8-pre7-alloc_super/kernel/sysctl.c
--- S8-pre7-freeing/kernel/sysctl.c Sat Apr 14 21:41:29 2001
+++ S8-pre7-alloc_super/kernel/sysctl.c Thu Aug 9 19:07:32 2001
@@ -286,10 +286,6 @@
0444, NULL, &proc_dointvec},
{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
0644, NULL, &proc_dointvec},
- {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
- 0444, NULL, &proc_dointvec},
- {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
- 0644, NULL, &proc_dointvec},
{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
0444, NULL, &proc_dointvec},
{FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] fs/super.c fixes (8/8)
2001-08-09 23:33 ` [PATCH] fs/super.c fixes (7/8) Alexander Viro
@ 2001-08-09 23:33 ` Alexander Viro
0 siblings, 0 replies; 8+ messages in thread
From: Alexander Viro @ 2001-08-09 23:33 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel
Part 8/8:
get_super() grabs shared lock on ->s_umount now. drop_super() releases it.
That provides exclusion with umount(), closing large part of get_super() races.
Callers updated.
diff -urN S8-pre7-alloc_super/fs/inode.c S8-pre7-get_super/fs/inode.c
--- S8-pre7-alloc_super/fs/inode.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-get_super/fs/inode.c Thu Aug 9 19:07:33 2001
@@ -357,11 +357,7 @@
spin_unlock(&inode_lock);
down_read(&s->s_umount);
if (!s->s_root) {
- up_read(&s->s_umount);
- spin_lock(&sb_lock);
- if (!--s->s_count)
- kfree(s);
- spin_unlock(&sb_lock);
+ drop_super(s);
goto restart;
}
return s;
@@ -388,23 +384,13 @@
*/
if (dev) {
if ((s = get_super(dev)) != NULL) {
- down_read(&s->s_umount);
- if (s->s_root)
- sync_inodes_sb(s);
- up_read(&s->s_umount);
- spin_lock(&sb_lock);
- if (!--s->s_count)
- kfree(s);
- spin_unlock(&sb_lock);
+ sync_inodes_sb(s);
+ drop_super(s);
}
} else {
while ((s = get_super_to_sync()) != NULL) {
sync_inodes_sb(s);
- up_read(&s->s_umount);
- spin_lock(&sb_lock);
- if (!--s->s_count)
- kfree(s);
- spin_unlock(&sb_lock);
+ drop_super(s);
}
}
}
@@ -636,13 +622,14 @@
int invalidate_device(kdev_t dev, int do_sync)
{
- struct super_block *sb = get_super(dev);
+ struct super_block *sb;
int res;
if (do_sync)
fsync_dev(dev);
res = 0;
+ sb = get_super(dev);
if (sb) {
res = invalidate_inodes(sb);
drop_super(sb);
diff -urN S8-pre7-alloc_super/fs/super.c S8-pre7-get_super/fs/super.c
--- S8-pre7-alloc_super/fs/super.c Thu Aug 9 19:07:32 2001
+++ S8-pre7-get_super/fs/super.c Thu Aug 9 19:07:33 2001
@@ -647,8 +647,23 @@
spin_unlock(&sb_lock);
}
+static inline struct super_block * find_super(kdev_t dev)
+{
+ struct list_head *p;
+
+ list_for_each(p, &super_blocks) {
+ struct super_block * s = sb_entry(p);
+ if (s->s_dev == dev) {
+ s->s_count++;
+ return s;
+ }
+ }
+ return NULL;
+}
+
void drop_super(struct super_block *sb)
{
+ up_read(&sb->s_umount);
__put_super(sb);
}
@@ -681,8 +696,7 @@
if (sb) {
if (sb->s_dirt)
write_super(sb);
- up_read(&sb->s_umount);
- __put_super(sb);
+ drop_super(sb);
}
return;
}
@@ -695,8 +709,7 @@
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
write_super(sb);
- up_read(&sb->s_umount);
- __put_super(sb);
+ drop_super(sb);
goto restart;
} else
sb = sb_entry(sb->s_list.next);
@@ -719,21 +732,19 @@
return NULL;
restart:
spin_lock(&sb_lock);
- s = sb_entry(super_blocks.next);
- while (s != sb_entry(&super_blocks))
- if (s->s_dev == dev) {
- /* Yes, it sucks. As soon as we get refcounting... */
- /* Almost there */
- s->s_count++;
- spin_unlock(&sb_lock);
- lock_super(s);
- unlock_super(s);
- if (s->s_dev == dev)
- return s;
- drop_super(s);
- goto restart;
- } else
- s = sb_entry(s->s_list.next);
+ s = find_super(dev);
+ if (s) {
+ spin_unlock(&sb_lock);
+ /* Yes, it sucks. As soon as we get refcounting... */
+ /* Almost there - next two lines will go away RSN */
+ lock_super(s);
+ unlock_super(s);
+ down_read(&s->s_umount);
+ if (s->s_root)
+ return s;
+ drop_super(s);
+ goto restart;
+ }
spin_unlock(&sb_lock);
return NULL;
}
@@ -908,10 +919,11 @@
spin_unlock(&sb_lock);
}
atomic_inc(&sb->s_active);
+ up_read(&sb->s_umount);
path_release(&nd);
return sb;
}
- __put_super(sb);
+ drop_super(sb);
} else {
mode_t mode = FMODE_READ; /* we always need it ;-) */
if (!(flags & MS_RDONLY))
@@ -1626,6 +1638,7 @@
/* FIXME */
fs_type = sb->s_type;
atomic_inc(&sb->s_active);
+ up_read(&sb->s_umount);
goto mount_it;
}
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2001-08-09 23:35 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-08-09 23:30 [PATCH] fs/super.c fixes (1/8) Alexander Viro
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (2/8) Alexander Viro
2001-08-09 23:31 ` [PATCH] fs/super.c fixes (3/8) Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (4/8) Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (5/8) Alexander Viro
2001-08-09 23:32 ` [PATCH] fs/super.c fixes (6/8) Alexander Viro
2001-08-09 23:33 ` [PATCH] fs/super.c fixes (7/8) Alexander Viro
2001-08-09 23:33 ` [PATCH] fs/super.c fixes (8/8) Alexander Viro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).