patch for 2.1.74 fs/super.c

Bill Hawes (whawes@star.net)
Sun, 21 Dec 1997 12:59:44 -0500


This is a multi-part message in MIME format.
--------------EAE0C9B12DF7FA1CC8B63853
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached patch for super.c makes a couple of changes to avoid
problems with locked superblocks.

In sync_supers, I've added a test for s_dirt before doing a wait.
There's no point in waiting on a locked superblock if it's not already
dirty, and this will keep the sync operation from being held up while a
device is being mounted.

I think it would be better to lock the superblock while doing the
writing, in order to prevent a race with unmounting while the write is
in progress. (Some filesystems are already doing this.) But this needs
further review ...

In read_super, I've added a test to make sure the empty superblock
doesn't have the s_lock flag set. Hopefully all the error exits leaving
superblocks locked have been fixed, but I'd prefer to test it here.

I've also cleared s_dirt in advance of the call to type->read_super to
make sure we don't get stuck waiting in sync_supers.

Regards,
Bill
--------------EAE0C9B12DF7FA1CC8B63853
Content-Type: text/plain; charset=us-ascii; name="super_74-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="super_74-patch"

--- fs/super.c.old Mon Dec 1 23:56:58 1997
+++ fs/super.c Sun Dec 21 12:43:59 1997
@@ -419,6 +419,11 @@
current->state = TASK_RUNNING;
}

+/*
+ * Note: check the dirty flag before waiting, so we don't
+ * hold up the sync while mounting a device. (The newly
+ * mounted device won't need syncing.)
+ */
void sync_supers(kdev_t dev)
{
struct super_block * sb;
@@ -428,6 +433,9 @@
continue;
if (dev && sb->s_dev != dev)
continue;
+ if (!sb->s_dirt)
+ continue;
+ /* N.B. Should lock the superblock while writing */
wait_on_super(sb);
if (!sb->s_dev || !sb->s_dirt)
continue;
@@ -444,13 +452,14 @@

if (!dev)
return NULL;
+restart:
s = 0+super_blocks;
while (s < NR_SUPER+super_blocks)
if (s->s_dev == dev) {
wait_on_super(s);
if (s->s_dev == dev)
return s;
- s = 0+super_blocks;
+ goto restart;
} else
s++;
return NULL;
@@ -494,33 +503,44 @@
struct file_system_type *type;

if (!dev)
- return NULL;
+ goto out_fail;
check_disk_change(dev);
s = get_super(dev);
if (s)
return s;
- if (!(type = get_fs_type(name))) {
+ type = get_fs_type(name);
+ if (!type) {
printk("VFS: on device %s: get_fs_type(%s) failed\n",
kdevname(dev), name);
- return NULL;
+ goto out_fail;
}
for (s = 0+super_blocks ;; s++) {
if (s >= NR_SUPER+super_blocks)
- return NULL;
- if (!(s->s_dev))
- break;
+ goto out_fail;
+ if (s->s_dev)
+ continue;
+ if (s->s_lock) {
+ printk("VFS: empty superblock %p locked!\n", s);
+ continue;
+ }
+ break;
}
s->s_dev = dev;
s->s_flags = flags;
- if (!type->read_super(s,data, silent)) {
- s->s_dev = 0;
- return NULL;
- }
- s->s_dev = dev;
- s->s_rd_only = 0;
s->s_dirt = 0;
+ /* N.B. Should lock superblock now ... */
+ if (!type->read_super(s,data, silent))
+ goto fail;
+ s->s_dev = dev; /* N.B. why do this again?? */
+ s->s_rd_only = 0;
s->s_type = type;
return s;
+
+ /* N.B. s_dev should be cleared in type->read_super */
+fail:
+ s->s_dev = 0;
+out_fail:
+ return NULL;
}

/*

--------------EAE0C9B12DF7FA1CC8B63853--