Jason Burrell wrote:
>
> I might be missing something, but it looks like filesystem
> mounts in 2.1.51-pre1 have a potentially major problem.
>
> I booted and typoed a mount command, mounting /dev/hdb1 on the mount point
> /.1 instead of /dev/hdc2 on /.1. I didn't catch this for a while, though,
> and the system happily mounted it.
>
> # df
> Filesystem 1024-blocks Used Available Capacity Mounted on
> /dev/hdb1 2970455 992404 1824434 35% /
> /dev/hdb1 2970455 992404 1824434 35% /.1
>
> And, of course, I can't umount it because it's busy.
The problem seems to be that the current fs_may_mount always returns
success, and when the system rereads the super_block, it gets a new root
dentry and so doesn't realize that the device is already mounted.
I've attached a patch for fs/super that should fix things up. Instead
of calling fs_may_mount, it checks whether the super_block and root
dentry are already present before reading the sb.
Incidentally, we may as well get rid of fs_xxx_mount, as they're no
longer used in the new scheme of things.
Regards,
Bill
--------------A3E5CC659524F456E3908F4E
Content-Type: text/plain; charset=us-ascii; name="super_mnt51-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="super_mnt51-patch"
--- fs/super.c.old Tue Aug 19 09:15:12 1997
+++ fs/super.c Wed Aug 20 09:19:03 1997
@@ -753,43 +760,50 @@
struct vfsmount *vfsmnt;
int error;
+ error = -EACCES;
if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
- return -EACCES;
+ goto out;
/*flags |= MS_RDONLY;*/
dir_d = namei(dir_name);
error = PTR_ERR(dir_d);
if (IS_ERR(dir_d))
- return error;
+ goto out;
+
+ error = -EBUSY;
+ if (dir_d->d_covers != dir_d)
+ goto dput_and_out;
+
+ error = -ENOTDIR;
+ if (!S_ISDIR(dir_d->d_inode->i_mode))
+ goto dput_and_out;
+
+ /*
+ * Check whether to read the super block
+ */
+ error = -EINVAL;
+ if (!(sb = get_super(dev)) || !sb->s_root)
+ sb = read_super(dev,type,flags,data,0);
+ if (!sb || !sb->s_root)
+ goto dput_and_out;
+
+ error = -EBUSY;
+ if (sb->s_root->d_covers != sb->s_root)
+ goto dput_and_out;
- if (dir_d->d_covers != dir_d) {
- dput(dir_d);
- return -EBUSY;
- }
- if (!S_ISDIR(dir_d->d_inode->i_mode)) {
- dput(dir_d);
- return -ENOTDIR;
- }
- if (!fs_may_mount(dev)) {
- dput(dir_d);
- return -EBUSY;
- }
- sb = read_super(dev,type,flags,data,0);
- if (!sb) {
- dput(dir_d);
- return -EINVAL;
- }
- if (sb->s_root->d_covers != sb->s_root) {
- dput(dir_d);
- return -EBUSY;
- }
vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
if (vfsmnt) {
vfsmnt->mnt_sb = sb;
vfsmnt->mnt_flags = flags;
}
+ /* N.B. what if add_vfsmnt failed?? */
d_mount(dir_d, sb->s_root);
return 0; /* we don't dput(dir) - see umount */
+
+dput_and_out:
+ dput(dir_d);
+out:
+ return error;
}
--------------A3E5CC659524F456E3908F4E--