[PATCH] link_path_walk refcount problem allows umount of active filesystem
Linux Kernel Mailing List <[email protected]> Fri, 25 Mar 2005 19:58:30 +0000
| Newsgroups | gmane.linux.kernel.commits.2-4 |
|---|---|
| Message-ID | <[email protected]> |
ChangeSet 1.1478, 2005/03/25 16:58:30-03:00, [email protected] [PATCH] link_path_walk refcount problem allows umount of active filesystem --=-fPp/ESy58Gj/36RjsLWj Content-Transfer-Encoding: 7bit Content-Type: text/plain G'day, The attached patch fixes a bug in the VFS code which causes "Busy inodes after unmount" and a subsequent oops. Greg. -- Greg Banks, R&D Software Engineer, SGI Australian Software Group. I don't speak for SGI. --=-fPp/ESy58Gj/36RjsLWj Content-Transfer-Encoding: 7bit Content-Type: text/x-patch; name=sgi932676-fix-link-following-vfsmount-refcount-bug.patch; charset=ISO-8859-1 Content-Disposition: attachment; filename=sgi932676-fix-link-following-vfsmount-refcount-bug.patch Following an absolute symlink opens a window during which the filesystem containing the symlink has an outstanding dentry count and no outstanding vfsmount count. A umount() of the filesystem can (incorrectly) proceed, resulting in the "Busy inodes after unmount" message and an oops shortly thereafter. Systems using autofs-controlled NFS mounts are especially vulnerable, as autofs both increases the number of unmounts happening and does NFS mounting in response to lookups which can result in multiple-second vulnerability windows. However the bug could happen on any filesystem. This patch adds a mntget()/mntput() pair around the link following code (as the 2.6 code does). Attempts to umount() during link following now return EBUSY. Signed-off-by: Greg Banks <[email protected]> namei.c | 7 +++++++ 1 files changed, 7 insertions(+) diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c 2005-03-25 20:04:03 -08:00 +++ b/fs/namei.c 2005-03-25 20:04:03 -08:00 @@ -540,8 +540,10 @@ goto out_dput; if (inode->i_op->follow_link) { + struct vfsmount *mnt = mntget(nd->mnt); err = do_follow_link(dentry, nd); dput(dentry); + mntput(mnt); if (err) goto return_err; err = -ENOENT; @@ -595,8 +597,10 @@ inode = dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { + struct vfsmount *mnt = mntget(nd->mnt); err = do_follow_link(dentry, nd); dput(dentry); + mntput(mnt); if (err) goto return_err; inode = nd->dentry->d_inode; @@ -1003,6 +1007,7 @@ int acc_mode, error = 0; struct inode *inode; struct dentry *dentry; + struct vfsmount *mnt; struct dentry *dir; int count = 0; @@ -1185,8 +1190,10 @@ * are done. Procfs-like symlinks just set LAST_BIND. */ UPDATE_ATIME(dentry->d_inode); + mnt = mntget(nd->mnt); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); + mntput(mnt); if (error) return error; if (nd->last_type == LAST_BIND) {