patch for 2.1.49 d_umount

Bill Hawes (whawes@star.net)
Thu, 14 Aug 1997 17:33:59 -0400


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

Attached is a patch to make some minor fixes to fs/super.c, exclusive of
the previously-posted do_change_root patch. Changes are:

(1) In d_umount, unconditionally dput() the root dentry. This is the
last reference to the root dentry, so we always want to dput() it, even
if for some reason it's not mounted.

(2) In do_umount, clear the sb->s_root pointer before calling d_umount.
The dput() in d_umount will block, temporarily exposing a stale pointer
accessible by finding the super block.

Also, test the dirty inode list and complain if any inodes are left.

(3) Other minor changes to check allocations of inodes and to make sure
dentry inode pointers aren't NULL.

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

--- fs/super.c.old Tue Aug 12 07:49:18 1997
+++ fs/super.c Thu Aug 14 08:08:31 1997
@@ -550,6 +550,9 @@
kdevname(dev));
}

+/*
+ * Always dput() the dentry, even if it's not mounted.
+ */
static void d_umount(struct dentry *dentry)
{
struct dentry * covers = dentry->d_covers;
@@ -558,8 +561,8 @@
covers->d_mounts = covers;
dentry->d_covers = dentry;
dput(covers);
- dput(dentry);
}
+ dput(dentry);
}

static void d_mount(struct dentry *covers, struct dentry *dentry)
@@ -575,6 +578,7 @@
static int do_umount(kdev_t dev,int unmount_root)
{
struct super_block * sb;
+ struct dentry * root;
int retval;

sb = get_super(dev);
@@ -599,8 +603,7 @@
quota_off(dev, -1);
fsync_dev(dev);
retval = do_remount_sb(sb, MS_RDONLY, 0);
- if (retval)
- return retval;
+ return retval;
}
return 0;
}
@@ -615,11 +618,16 @@
return -EBUSY;

/* clean up dcache .. */
- d_umount(sb->s_root);
- sb->s_root = NULL;
+ root = sb->s_root;
+ sb->s_root = NULL; /* d_umount() may block ... */
+ d_umount(root);

/* Forget any inodes */
invalidate_inodes(dev);
+ if (!list_empty(&sb->s_dirty)) {
+ printk("VFS: super block %s has dirty inodes\n",
+ kdevname(sb->s_dev));
+ }

if (sb->s_op) {
if (sb->s_op->write_super && sb->s_dirt)
@@ -631,15 +639,27 @@
return 0;
}

+/*
+ * There is a little kludge here with the empty inode. The current
+ * vfs release functions only use the r_dev field in the inode so
+ * we give them the info they need without using a real inode.
+ * If any other fields are ever needed by any block device release
+ * functions, they should be faked here. -- jrs
+ */
static int umount_dev(kdev_t dev)
{
int retval;
struct inode * inode = get_empty_inode();

- inode->i_rdev = dev;
+ retval = -ENOMEM;
+ if (!inode)
+ goto out;
+
+ retval = -ENXIO;
if (MAJOR(dev) >= MAX_BLKDEV)
- return -ENXIO;
+ goto out_iput;

+ inode->i_rdev = dev;
fsync_dev(dev);
retval = do_umount(dev,0);
if (!retval) {
@@ -649,21 +669,16 @@
put_unnamed_dev(dev);
}
}
+out_iput:
iput(inode);
+out:
return retval;
}

/*
* Now umount can handle mount points as well as block devices.
* This is important for filesystems which use unnamed block devices.
- *
- * There is a little kludge here with the dummy_inode. The current
- * vfs release functions only use the r_dev field in the inode so
- * we give them the info they need without using a real inode.
- * If any other fields are ever needed by any block device release
- * functions, they should be faked here. -- jrs
*/
-
asmlinkage int sys_umount(char * name)
{
struct dentry * dentry;
@@ -677,18 +692,22 @@
retval = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
struct inode * inode = dentry->d_inode;
- kdev_t dev = inode->i_rdev;
+ kdev_t dev = 0;

- retval = 0;
- if (S_ISBLK(inode->i_mode)) {
- if (IS_NODEV(inode))
- retval = -EACCES;
- } else {
- struct super_block *sb = inode->i_sb;
- retval = -EINVAL;
- if (sb && inode == sb->s_root->d_inode) {
- dev = sb->s_dev;
- retval = 0;
+ retval = -EINVAL;
+ if (inode) {
+ dev = inode->i_rdev;
+ retval = 0;
+ if (S_ISBLK(inode->i_mode)) {
+ if (IS_NODEV(inode))
+ retval = -EACCES;
+ } else {
+ struct super_block *sb = inode->i_sb;
+ retval = -EINVAL;
+ if (sb && inode == sb->s_root->d_inode) {
+ dev = sb->s_dev;
+ retval = 0;
+ }
}
}
dput(dentry);
@@ -808,11 +827,15 @@
dentry = namei(dir);
retval = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
- struct super_block * sb = dentry->d_inode->i_sb;
+ struct inode * inode = dentry->d_inode;
+ struct super_block * sb;

retval = -EINVAL;
- if (dentry == sb->s_root)
- retval = do_remount_sb(sb, flags, data);
+ if (inode) {
+ sb = inode->i_sb;
+ if (sb && dentry == sb->s_root)
+ retval = do_remount_sb(sb, flags, data);
+ }
dput(dentry);
}
return retval;

--------------D2442E8004AA8E922A0861C1--