From: Josef Bacik <jbacik@redhat.com> Date: Thu, 22 May 2008 11:29:35 -0400 Subject: [fs] debugfs: fix dentry reference count bug Message-id: 20080522152935.GA2449@unused.rdu.redhat.com O-Subject: [RHEL5.3 PATCH] debugfs: fix dentry reference count bug Bugzilla: 445787 RH-Acked-by: Jeff Moyer <jmoyer@redhat.com> Hello, This is in reference to 445787. Apparently oracle has a case where they can call debugfs_create_by_name twice, and when they do debugfs_remove() won't remove the file because the dentry was dget()'ed twice, and only dput()'ed once. This patch is a backport of commits 29a7f3ada7fea5510504c5359c3f70d109aeb055 65c333367b1aea57d58168ad3dc1df27b0227401 The second one moves the dput() to the creation path, as lookup_one_len() will do a dget and debugfs_mknod will also do a dget. The first commit fixes a remove bug that was reported in the same code that I figured I'd go ahead and backport while I was there. Thank you, Josef diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 0388882..6ad1b27 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -152,6 +152,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, error = debugfs_mkdir(parent->d_inode, *dentry, mode); else error = debugfs_create(parent->d_inode, *dentry, mode); + dput(*dentry); } else error = PTR_ERR(dentry); mutex_unlock(&parent->d_inode->i_mutex); @@ -197,13 +198,15 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, pr_debug("debugfs: creating file '%s'\n",name); - error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count); + error = simple_pin_fs(&debug_fs_type, &debugfs_mount, + &debugfs_mount_count); if (error) goto exit; error = debugfs_create_by_name(name, mode, parent, &dentry); if (error) { dentry = NULL; + simple_release_fs(&debugfs_mount, &debugfs_mount_count); goto exit; } @@ -264,7 +267,8 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir); void debugfs_remove(struct dentry *dentry) { struct dentry *parent; - + int ret = 0; + if (!dentry) return; @@ -275,11 +279,14 @@ void debugfs_remove(struct dentry *dentry) mutex_lock(&parent->d_inode->i_mutex); if (debugfs_positive(dentry)) { if (dentry->d_inode) { + dget(dentry); if (S_ISDIR(dentry->d_inode->i_mode)) - simple_rmdir(parent->d_inode, dentry); + ret = simple_rmdir(parent->d_inode, dentry); else simple_unlink(parent->d_inode, dentry); - dput(dentry); + if (!ret) + d_delete(dentry); + dput(dentry); } } mutex_unlock(&parent->d_inode->i_mutex);