patch-2.1.81 linux/fs/super.c

Next file: linux/fs/vfat/namei.c
Previous file: linux/fs/smbfs/proc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.80/linux/fs/super.c linux/fs/super.c
@@ -95,28 +95,37 @@
 	/* NOTREACHED */
 }
 
-struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name)
+static struct vfsmount *add_vfsmnt(struct super_block *sb,
+			const char *dev_name, const char *dir_name)
 {
 	struct vfsmount *lptr;
-	char *tmp;
+	char *tmp, *name;
 
 	lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
-        if (!lptr)
-		return NULL;
+	if (!lptr)
+		goto out;
 	memset(lptr, 0, sizeof(struct vfsmount));
 
-	lptr->mnt_dev = dev;
+	lptr->mnt_sb = sb;
+	lptr->mnt_dev = sb->s_dev;
+	lptr->mnt_flags = sb->s_flags;
 	sema_init(&lptr->mnt_sem, 1);
+
+	/* N.B. Is it really OK to have a vfsmount without names? */
 	if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
-		if ((lptr->mnt_devname =
-		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
-			strcpy(lptr->mnt_devname, tmp);
+		name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+		if (name) {
+			strcpy(name, tmp);
+			lptr->mnt_devname = name;
+		}
 		putname(tmp);
 	}
 	if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
-		if ((lptr->mnt_dirname =
-		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
-			strcpy(lptr->mnt_dirname, tmp);
+		name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+		if (name) {
+			strcpy(name, tmp);
+			lptr->mnt_dirname = name;
+		}
 		putname(tmp);
 	}
 
@@ -126,10 +135,11 @@
 		vfsmnttail->mnt_next = lptr;
 		vfsmnttail = lptr;
 	}
-	return (lptr);
+out:
+	return lptr;
 }
 
-void remove_vfsmnt(kdev_t dev)
+static void remove_vfsmnt(kdev_t dev)
 {
 	struct vfsmount *lptr, *tofree;
 
@@ -496,6 +506,23 @@
 	return err;
 }
 
+/*
+ * Find a super_block with no device assigned.
+ */
+static struct super_block *get_empty_super(void)
+{
+	struct super_block *s = 0+super_blocks;
+
+	for (; s < NR_SUPER+super_blocks; s++) {
+		if (s->s_dev)
+			continue;
+		if (!s->s_lock)
+			return s;
+		printk("VFS: empty superblock %p locked!\n", s);
+	}
+	return NULL;
+}
+
 static struct super_block * read_super(kdev_t dev,const char *name,int flags,
 				       void *data, int silent)
 {
@@ -503,44 +530,39 @@
 	struct file_system_type *type;
 
 	if (!dev)
-		goto out_fail;
+		goto out_null;
 	check_disk_change(dev);
 	s = get_super(dev);
 	if (s)
-		return s;
+		goto out;
+
 	type = get_fs_type(name);
 	if (!type) {
 		printk("VFS: on device %s: get_fs_type(%s) failed\n",
 		       kdevname(dev), name);
-		goto out_fail;
-	}
-	for (s = 0+super_blocks ;; s++) {
-		if (s >= NR_SUPER+super_blocks)
-			goto out_fail;
-		if (s->s_dev)
-			continue;
-		if (s->s_lock) {
-			printk("VFS: empty superblock %p locked!\n", s);
-			continue;
-		}
-		break;
+		goto out;
 	}
+	s = get_empty_super();
+	if (!s)
+		goto out;
 	s->s_dev = dev;
 	s->s_flags = flags;
 	s->s_dirt = 0;
 	/* N.B. Should lock superblock now ... */
-	if (!type->read_super(s,data, silent))
-		goto fail;
+	if (!type->read_super(s, data, silent))
+		goto out_fail;
 	s->s_dev = dev; /* N.B. why do this again?? */
 	s->s_rd_only = 0;
 	s->s_type = type;
+out:
 	return s;
 
 	/* N.B. s_dev should be cleared in type->read_super */
-fail:
-	s->s_dev = 0;
 out_fail:
-	return NULL;
+	s->s_dev = 0;
+out_null:
+	s = NULL;
+	goto out;
 }
 
 /*
@@ -603,17 +625,16 @@
 	dentry->d_covers = covered;
 }
 
-static int do_umount(kdev_t dev,int unmount_root)
+static int do_umount(kdev_t dev, int unmount_root)
 {
 	struct super_block * sb;
 	int retval;
 	
+	retval = -ENOENT;
 	sb = get_super(dev);
-	if (!sb)
-		return -ENOENT;
+	if (!sb || !sb->s_root)
+		goto out;
 
-	if (!sb->s_root)
-		return -ENOENT;
 	/*
 	 * Before checking whether the filesystem is still busy,
 	 * make sure the kernel doesn't hold any quotafiles open
@@ -659,7 +680,6 @@
 			sb->s_op->put_super(sb);
 	}
 	remove_vfsmnt(dev);
-	retval = 0;
 out:
 	return retval;
 }
@@ -781,7 +801,7 @@
 
 int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
 {
-	struct dentry * dir_d = NULL;
+	struct dentry * dir_d;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
 	int error;
@@ -806,15 +826,13 @@
 		goto dput_and_out;
 
 	/*
-	 * Check whether to read the super block
+	 * Note: If the superblock already exists,
+	 * read_super just does a get_super().
 	 */
-	sb = get_super(dev);
-	if (!sb || !sb->s_root) {
-		error = -EINVAL;
-		sb = read_super(dev,type,flags,data,0);
-		if (!sb)
-			goto dput_and_out;
-	}
+	error = -EINVAL;
+	sb = read_super(dev, type, flags, data, 0);
+	if (!sb)
+		goto dput_and_out;
 
 	/*
 	 * We may have slept while reading the super block, 
@@ -825,20 +843,19 @@
 		goto dput_and_out;
 
 	error = -ENOMEM;
-	vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
-	if (vfsmnt) {
-		vfsmnt->mnt_sb = sb;
-		vfsmnt->mnt_flags = flags;
-		d_mount(dir_d, sb->s_root);
-		error = 0;
-		goto out;		/* we don't dput(dir) - see umount */
-	}
+	vfsmnt = add_vfsmnt(sb, dev_name, dir_name);
+	if (!vfsmnt)
+		goto dput_and_out;
+	d_mount(dir_d, sb->s_root);
+	error = 0;	/* we don't dput(dir_d) - see umount */
 
-dput_and_out:
-	dput(dir_d);
 out:
 	up(&mount_sem);
 	return error;	
+
+dput_and_out:
+	dput(dir_d);
+	goto out;
 }
 
 
@@ -1063,14 +1080,11 @@
 	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
 		ROOT_DEV = 0;
 		if ((fs_type = get_fs_type("nfs"))) {
-			if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"))) {
-
-				sb = &super_blocks[0];
-				while (sb->s_dev) sb++;
-				vfsmnt->mnt_sb = sb;
-
-				sb->s_dev = get_unnamed_dev();
-				sb->s_flags = root_mountflags & ~MS_RDONLY;
+			sb = get_empty_super(); /* "can't fail" */
+			sb->s_dev = get_unnamed_dev();
+			sb->s_flags = root_mountflags & ~MS_RDONLY;
+			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
+			if (vfsmnt) {
 				if (nfs_root_mount(sb) >= 0) {
 					sb->s_rd_only = 0;
 					sb->s_dirt = 0;
@@ -1081,9 +1095,10 @@
 					printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
 					return;
 				}
-				sb->s_dev = 0;
-				put_unnamed_dev(sb->s_dev);
+				remove_vfsmnt(sb->s_dev);
 			}
+			put_unnamed_dev(sb->s_dev);
+			sb->s_dev = 0;
 		}
 		if (!ROOT_DEV) {
 			printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
@@ -1136,12 +1151,10 @@
 			printk ("VFS: Mounted root (%s filesystem)%s.\n",
 				fs_type->name,
 				(sb->s_flags & MS_RDONLY) ? " readonly" : "");
-			vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
-			if (!vfsmnt)
-				panic("VFS: add_vfsmnt failed for root fs");
-			vfsmnt->mnt_sb = sb;
-			vfsmnt->mnt_flags = root_mountflags;
-			return;
+			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
+			if (vfsmnt)
+				return;
+			panic("VFS: add_vfsmnt failed for root fs");
 		}
 	}
 	panic("VFS: Unable to mount root fs on %s",
@@ -1225,10 +1238,8 @@
 		return error;
 	}
 	remove_vfsmnt(old_root_dev);
-	vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
+	vfsmnt = add_vfsmnt(old_root->d_sb, "/dev/root.old", put_old);
 	if (vfsmnt) {
-		vfsmnt->mnt_sb = old_root->d_inode->i_sb;
-		vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;
 		d_mount(dir_d,old_root);
 		return 0;
 	}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov